Thread实现多线程死锁同步锁

Posted snzd9958

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Thread实现多线程死锁同步锁相关的知识,希望对你有一定的参考价值。

1、实现一个类MyThread继承Thread并重写run()方法
启动线程方法:实例化MyThread对象,并调用start()方法
多个线程之间交替执行(抢时间片)
主线程(main方法)有优先运行的权限,但并不绝对

2、实现一个类MyThread实现Runnable接口下的run()方法
启动线程方法:实例化MyThread对象mt,并将mt作为实例化Thread的参数,再通过Thread对象调用start()方法
MyThread mt = new MyThread();
Thread t = new Thread(mt);
t.start();

实现点击按钮,球向前慢慢滚动的效果:
public class Test extends JFrame{

    private MyPanel mp;
    public static void main(String[] args) {
        new Test().setVisible(true);

    }
    private JPanel panel;
    private JButton btn;
    public Test() {
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new JPanel();
        panel.setLayout(new BorderLayout());
        setBounds(300, 100, 600, 300);
        this.setContentPane(panel);
        
        mp = new MyPanel();
        panel.add(mp);
        
        btn = new JButton("开始");
        
        btn.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                
                Thread t = new Thread(mp);
                t.start();
                
            }
        });
        panel.add(btn,BorderLayout.SOUTH);
    }
    
    private class MyPanel extends JPanel implements Runnable{

        private int x = 100;
        public void paint(Graphics g) {
            super.paint(g);
            g.fillOval(x, 80, 50, 50);
        }
        @Override
        public void run() {
            for (int i = 0; i < 50; i++) {
                x += 5 ;
                try {
                    Thread.sleep(150);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                repaint();
            }
            
        }
    }
}

3、使用匿名类,继承Thread,重写run()方法,直接在run()方法中写业务代码
匿名类的一个好处是可以很方便的访问外部的局部变量
public class TestThread {
  
    public static void main(String[] args) {
          
        Hero gareen = new Hero();
        gareen.name = "盖伦";
        gareen.hp = 616;
        gareen.damage = 50;
  
        Hero teemo = new Hero();
        teemo.name = "提莫";
        teemo.hp = 300;
        teemo.damage = 30;
          
        Hero bh = new Hero();
        bh.name = "赏金猎人";
        bh.hp = 500;
        bh.damage = 65;
          
        Hero leesin = new Hero();
        leesin.name = "盲僧";
        leesin.hp = 455;
        leesin.damage = 80;
          
        //匿名类
        Thread t1= new Thread(){
            public void run(){
                //匿名类中用到外部的局部变量teemo,必须把teemo声明为final
                //但是在JDK7以后,就不是必须加final的了
                while(!teemo.isDead()){
                    gareen.attackHero(teemo);
                }              
            }
        };
         
        t1.start();
          
        Thread t2= new Thread(){
            public void run(){
                while(!leesin.isDead()){
                    bh.attackHero(leesin);
                }              
            }
        };
        t2.start();
         
    }
      
}

注意: 启动线程是start()方法,run()并不能启动一个新的线程

常见线程方法:

sleep    当前线程暂停
Thread.sleep(1000); 表示当前线程暂停1000毫秒 ,其他线程不受影响 

join    加入到当前线程中
Thread t1= new Thread(){
            public void run(){
                while(!teemo.isDead()){
                    gareen.attackHero(teemo);
                }
            }
        };
t1.start();
try {
 //main线程在运行时,t1线程加入到main线程中来,只有t1线程运行结束,才会继续往下走
      t1.join();
} catch (InterruptedException e) {
e.printStackTrace();

}

setPriority    线程优先级
当线程处于竞争关系的时候,优先级高的线程会有更大的几率获得CPU资源 
Thread t1 = new Thread();
Thread t2 = new Thread();
t1.setPriority(Thread.MAX_PRIORITY);最大为10
t2.setPriority(Thread.MIN_PRIORITY);最小为0

yield    临时暂停    
当前线程,临时暂停,使得其他线程可以有更多的机会占用CPU资源

setDaemon    守护线程
如果一个进程只剩下守护线程,那么进程就会自动结束。


线程同步

没有实现同步
public class Bank {

    public static void main(String[] args) {
        new Bank().way();

    }

    public void way() {
        Family f = new Family();
        Thread t1 = new Thread(f, "丈夫");

        //new Thread(f, "线程名称");
        Thread t2 = new Thread(f, "妻子");
        t1.start();
        t2.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        while (true) {
            if (f.times >= 2) {
                f.show();
                break;
            }
        }

    }

    private class Family implements Runnable {
        private int totalMoney;
        private int getMoney;
        private int currentMoney;
        private int times = 0;
        private Object key = new Object();

        public Family() {
            totalMoney = 5000;
            getMoney = 2000;
            currentMoney = 0;
        }

        @Override
        public void run() {

            //Thread.currentThread()当前线程
            System.out.println(Thread.currentThread().getName() + "---取了" + getMoney + "元");
            //给取出的钱重新赋值
            currentMoney += getMoney;
            
            //银行存款剩余
            int tem = totalMoney - getMoney;
            
            //在银行存款变换之前,线程沉睡1s,这时,时间片被另一个线程抢走
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
             //给银行存款重新赋值
            totalMoney = tem;
            times++;
        }
        
        public void show() {
            System.out.println("银行存款剩余:" + totalMoney + " 取出:" + currentMoney);
        }
    }
}
运行:
丈夫---取了2000元
妻子---取了2000元
银行存款剩余:3000    取出:4000

添加同步锁:
    方法一:
        //对象必须在run()方法体外面
        private Object key = new Object();

        public void run() {
            //synchronized( 可以是任意对象,例如:this)
            synchronized (key) {
                System.out.println(Thread.currentThread().getName() + "---取了" + getMoney + "元");
                currentMoney += getMoney;
                int tem = totalMoney - getMoney;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                totalMoney = tem;
                times++;
            }

        }

    方法二:
        public void run() {
            
            syn();

        }
        public synchronized void syn() {
            System.out.println(Thread.currentThread().getName() + "---取了" + getMoney + "元");
            currentMoney += getMoney;
            int tem = totalMoney - getMoney;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            totalMoney = tem;
            times++;
        }
运行:
丈夫---取了2000元
妻子---取了2000元
银行存款剩余:1000    取出:4000


死锁

1. 线程1 首先占有对象1,接着试图占有对象2
2. 线程2 首先占有对象2,接着试图占有对象1
3. 线程1 等待线程2释放对象2
4. 与此同时,线程2等待线程1释放对象1
就会。。。一直等待下去,直到天荒地老,海枯石烂,山无棱 ,天地合。。。

public class Test04 {

    public static void main(String[] args) {
        new Test04();

    }
    public Test04() {
        MyThread mt = new MyThread();
        Thread t1 = new Thread(mt,"A");
        Thread t2 = new Thread(mt,"B");
        t1.start();t2.start();
    }
    public class MyThread implements Runnable{
        private Object o1 = new Object();
        private Object o2 = new Object();
        private boolean b = false;
        @Override
        public void run() {
            if(b) {
                b = !b;
                synchronized (o1) {
                    System.out.println(Thread.currentThread().getName()+"拿到第一把钥匙!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    synchronized (o2) {
                        System.out.println(Thread.currentThread().getName()+"拿到第二把钥匙!");
                    }
                }
            }else {
                b = !b;
                synchronized (o2) {
                    System.out.println(Thread.currentThread().getName()+"拿到第二把钥匙!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    synchronized (o1) {
                        System.out.println(Thread.currentThread().getName()+"拿到第一把钥匙!");
                    }
                }
            }
            
        }
        
    }

}
运行:
B拿到第一把钥匙!
A拿到第二把钥匙!
(一直在运行中,程序没有结束!)
























































































































































































































































































以上是关于Thread实现多线程死锁同步锁的主要内容,如果未能解决你的问题,请参考以下文章

4-5 《Java中多线程重点》——继承Thread实现Runnable死锁线程池Lambda表达式

同步函数死锁现象

高并发基石多线程守护线程线程安全线程同步互斥锁

一个多线程死锁案例,如何避免及解决死锁问题?

同步锁 死锁 递归锁

day18-多线程&线程同步&死锁