• 多线程知识点


    题目:

    请编写一个多线程程序,实现两个线程,其中一个线程完成对某个对象的int类型成员变量的增加操作,即每次加1;另一个线程完成对成员变量的减小操作,即每次减1,同时保证该变量的值不会小于0,不会大于1,该变量的初始值为0。

    包含int类型成员变量的类:

    public class Test {
    
        // int类型成员变量
        private int num;
        
        // 增加
        public synchronized void increase() {
            if(num != 0) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            num ++;
            System.out.println("increase :" + num);
            notify();
        }
        
        // 减小
        public synchronized void decrease() {
            if(num == 0) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            num --;
            System.out.println("decrease :" + num);
            notify(); 
        }
    }
    View Code

    增加成员变量的线程:

    /**
     * 增加线程,直接继承自Thread,也可实现Runnable接口
     * @author Wu
     *
     */
    public class IncreaseThread extends Thread{
    
        private Test test;
        
        public IncreaseThread(Test test) {
            this.test = test;
        }
        
        @Override
        public void run() {
            for(int i = 0; i < 10; i ++) {
                test.increase();
            }
        }
    }
    View Code

    减少成员变量的线程:

    /**
     * 减少线程,直接继承自Thread,也可实现Runnable接口
     * @author Wu
     *
     */
    public class DecreaseThread extends Thread{
    
        private Test test;
        
        public DecreaseThread(Test test) {
            this.test = test;
        }
        
        @Override
        public void run() {
            for(int i = 0; i < 10; i ++) {
                test.decrease();
            }
        }
        
    }
    View Code

    测试程序:

          
    class Main {      
        public static void main(String[] args) {      
            Test test = new Test();
            
            Thread t1 = new IncreaseThread(test);
            Thread t2 = new DecreaseThread(test);
            
            t1.start();
            t2.start();
            
            
        }
    }      
    View Code

    测试结果

    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    increase :1
    decrease :0
    View Code

    总结

    一、关于wait,notify,notifyAll以及sleep方法的关系。

    1、如果一个线程调用了某个对象的wait方法,那么该线程首先必须要拥有该对象的锁(换句话说,一个线程如果调用了某个对象的wait,那么该wait方法必须要在synchronized中)。

    2、如果一个线程调用了某个对象的wait方法,那么该线程就会释放该对象的锁。

    3、在Java对象中,有两种池(锁池、等待池)。

    4、如果一个线程调用了某个对象的wait方法,那么该线程进入该对象的等待池中(释放锁),如果未来某个时刻,另外一个线程调用了相同的对象的notify或者notifyAll方法,那么在该等待池中的等待的线程就会起来进入该对象的 锁池中,去等待获得该对象的锁,如果获得锁成功,那么该线程将继续沿着wait方法之后的路径去执行。

    5、如果一个线程调用了sleep方法睡眠,那么在睡眠的同时,它不会失去对象的锁的拥有权。

    二、关于synchronized关键字的作用。

    1、在某个对象的所有synchronized方法中,在某一时刻,只能有一个唯一的线程去访问这些synchronized方法。

    /**
     * 线程t1先执行,即使睡了2秒钟,线程t2也必须等待t1释放锁,才能访问test对象的synchronized方法     
     * @author Wu
     *
     */
    class Main {      
        public static void main(String[] args) {      
            Test test = new Test();
            Thread t1 = new Thread(new Thread1(test));
            Thread t2 = new Thread(new Thread2(test));
            
            t1.start();
            t2.start();
            
        }
    }     
    class Thread1 implements Runnable {
        Test test;
        public Thread1(Test test) {
            this.test = test;
        }
        @Override
        public void run() {
            test.hello();
        }
        
    }
    
    class Thread2 implements Runnable {
        Test test;
        public Thread2(Test test) {
            this.test = test;
        }
        @Override
        public void run() {
            test.world();
        }
        
    }
    class Test {
        public synchronized void hello() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("hello");
        }
        
        public synchronized void world() {
            System.out.println("world");
        }
    }
    View Code

    2、如果有一个方法时synchronized方法,那么该synchronized关键字表示给当前对象上锁。

    3、如果一个synchronized方法是静态的,那么该synchronized关键字表示给当前对象所对应的Class对象上锁(每个类不管生成多少个对象,其对应的Class对象只有一个)。

    
    
    class Main {      
        public static void main(String[] args) {      
            Test test1 = new Test();
            Thread t1 = new Thread(new Thread1(test1));
            Test test2 = new Test();
            Thread t2 = new Thread(new Thread2(test2));
            
            t1.start();
            t2.start();
            
        }
    }     
    class Thread1 implements Runnable {
        Test test;
        public Thread1(Test test) {
            this.test = test;
        }
        @Override
        public void run() {
            test.hello();
        }
        
    }
    
    class Thread2 implements Runnable {
        Test test;
        public Thread2(Test test) {
            this.test = test;
        }
        @Override
        public void run() {
            test.world();
        }
        
    }
    class Test {
        public static synchronized void hello() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("hello");
        }
        
        public static synchronized void world() {
            System.out.println("world");
        }
    }
    View Code
    
    
  • 相关阅读:
    nginx设置开机自启
    sublimeText3和phpstrom使用
    快捷键整理
    nginx日志分割及备份
    nginx日志设置
    nginx上部署PHP
    C语言三种参数传递方式
    浮点数在内存中的存储方式
    windows下git安装过程
    偏移二进制编码和二进制补码的区别
  • 原文地址:https://www.cnblogs.com/zywu/p/5801922.html
Copyright © 2020-2023  润新知