zoukankan      html  css  js  c++  java
  • Java 线程同步方式

    相关连接: https://blog.csdn.net/wojiushiwo945you/article/details/42292999

    https://www.cnblogs.com/dolphin0520/p/3920373.html

    https://www.cnblogs.com/qifengshi/p/6831055.html

    相关概念:

    1,独占资源和共享资源。这里说的独占和共享,是指是否只有一个线程可以占有这个锁。独占并不是说这个资源只可以lock一次,有可能一个线程可以lock多次,这被叫做可重入。

    2.,公平、非公平。一个锁资源是否应该按照线程申请的先后顺序分配,还是允许后申请的线程先获得锁。前者是公平锁,后者叫非公平锁。

    3,并发相关的三原则:原子性、可见性、有序性。原子性指一组操作不可分割,要么执行,要么不执行。计算机的rom分高速缓存和主存。Java中线程会有一个工作内存,当变量的值被修改的时候,可能只写入了线程相关的高速缓存,而没有写去主存。这种情况下,其他线程读取不到正确的数值。这样的现象成为变量不可见。有序性是关于Java指令重排的。Java的指令重排可能会引发多线程数据异常,例如 一个 初始化操作在状态变量标记为完成后才执行。

    volatile 修饰的变量具有可见性,它的修改会被直接写入主存。 java指令重排的时候不会重排volatile语句,写在volatile语句(读或写)之前的语句一定在volatile语句之前执行,写在之后的一定在volatile语句之后执行。

    volatile应用场景,标记状态量,double check

    公平锁举例:new ReentrantLock(true)

    非公平锁举例:new ReentrantLock(false)、synchronized

    独享锁举例:ReentrantLock、synchronized 

    注意点:资源的释放需要在finally语句中进行。

    Java中synchronized关键字锁定的是对象。验证代码如下:

    class Demo
    {
        public synchronized void  sayHello(){
            try{
                System.out.println("hello start");
                Thread.sleep(100);
                System.out.println("hello end");
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    
        public synchronized void doAction()
        {
            try{
                System.out.println("put up hand");
                Thread.sleep(100);
                System.out.println("put down hand");
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    
    public class Test {
        public static void main(String[] args)
        {
            Demo demo = new Demo();
            Demo demoA = new Demo();
            Thread sayThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo.sayHello();
                }
            });
    
            Thread actionThread = new Thread(new Runnable() {
                @Override
                public void run() {
    //                demo.doAction();
                    demoA.doAction();
                }
            });
    
            sayThread.start();
            actionThread.start();
        }
    }
    

    三种情况:

    1、两个线程都使用demo变量,方法用synchronized修饰。 结果: sayHello和doAction一定是一个执行完另一个才执行。

    2,两个线程都使用demo变量,方法不使用synchronized修饰。结果:sayHello和doAction可以交叉执行。

    3、两个线程分别使用demo和demoA变量,方法用synchronized修饰。 结果: sayHello和doAction可以交叉执行。

     synchronized 和 static 同时修饰一个方法

    class Worker
    {
        public static synchronized void doWork(String name)
        {
            try {
                System.out.println(name+ " starts a work");
                Thread.sleep(100);
                System.out.println(name+ " finish a work");
            }catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    public class Test {
        public static void main(String[]args)
        {
    
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    new Worker().doWork("zhangsan");
                }
            });
    
            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    new Worker().doWork("lisi");
                }
            });
    
            threadA.start();
            threadB.start();
        }
    
    }
    

      

    Semaphore 用法:

    import java.util.concurrent.Semaphore;
    
    class PreTask implements Runnable
    {
        private Semaphore sem;
        private int weight;
        PreTask(Semaphore sem, int weight){
            this.sem = sem;
            this.weight = weight;
        }
        public void run()
        {
            try{
                System.out.println("a pretask starts");
                Thread.sleep(100);
                System.out.println("a pretask is done which weight is "+this.weight);
                
            }catch (InterruptedException e){
                e.printStackTrace();
            }finally{
    // 在finally中释放资源
    this.sem.release(this.weight);
    }
    } } class LateTask implements Runnable { private Semaphore sem; private int requireWeight; LateTask(Semaphore sem, int requireWeight) { this.sem = sem; this.requireWeight = requireWeight; } public void run() { try{ this.sem.acquire(this.requireWeight); System.out.println("a latetask starts"); Thread.sleep(100); System.out.println("a latetask is done which requireWeight is "+this.requireWeight); }catch (InterruptedException e){ e.printStackTrace(); } } } public class Test { public static void main(String[] args) { Semaphore semaphore = new Semaphore(0); PreTask preA = new PreTask(semaphore, 1); PreTask preB = new PreTask(semaphore, 3); LateTask late = new LateTask(semaphore, 4); Thread preThreadA = new Thread(preA); Thread preThreadB = new Thread(preB); Thread lateThreadB = new Thread(late); preThreadA.start(); preThreadB.start(); lateThreadB.start(); } }

     输出结果如下:

    a pretask starts
    a pretask starts
    a pretask is done which weight is 3
    a pretask is done which weight is 1
    a latetask starts
    a latetask is done which requireWeight is 4

    import java.util.concurrent.Semaphore;
    
    class User implements Runnable
    {
        private Semaphore sem;
        private String name;
        User(Semaphore sem, String name){
            this.sem = sem;
            this.name = name;
        }
        public void run()
        {
            try{
                this.sem.acquire(1);
                System.out.println(this.name+" take up a pen");
                Thread.sleep(100);
                System.out.println(this.name+" put down a pen ");
                
            }catch (InterruptedException e){
                e.printStackTrace();
            }finally{
    //在finally中释放资源
    this.sem.release(1);

    } } } public class Test { public static void main(String[] args) { Semaphore penSet = new Semaphore(2); User zhangsan = new User(penSet, "zhangsan"); User lisi = new User(penSet, "lisi"); User wangwu = new User(penSet, "wangwu"); User zhaoliu = new User(penSet, "zhaoliu"); Thread threadZhangsan = new Thread(zhangsan); Thread threadL = new Thread(lisi); Thread threadW = new Thread(wangwu); Thread threadZhaoliu = new Thread(zhaoliu); threadZhangsan.start(); threadL.start(); threadW.start(); threadZhaoliu.start(); } }

     结果:最多同时有两个人在使用铅笔

     Semaphore tryAquire,尝试获取一个数量的资源,这个方法是非阻塞的,返回一个boolean值表示是否获得了资源。

    import java.util.concurrent.Semaphore;
    
    class Worker
    {
        public void doWork(Semaphore tool, String name)
        {
            if (tool.tryAcquire(1))
            {
                try {
                    System.out.println(name+ " starts a work with tool");
                    Thread.sleep(100);
                    System.out.println(name+ " finish a work and release tool");
                }catch (InterruptedException e)
                {
                    e.printStackTrace();
                }finally {
                    tool.release();
                }
            }else
            {
                try {
                    System.out.println(name+ " starts a work with hand");
                    Thread.sleep(500);
                    System.out.println(name+ " finish a work ");
                }catch (InterruptedException e)
                {
                    e.printStackTrace();
                }finally {
                }
            }
    
        }
    }
    
    public class Test {
        public static void main(String[]args)
        {
            Semaphore tool = new Semaphore(1);
    
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    new Worker().doWork(tool,"zhangsan");
                }
            });
    
            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    new Worker().doWork(tool,"lisi");
                }
            });
    
            threadA.start();
            threadB.start();
        }
    
    }
    

      

    两个人可以同时工作,但同一时间只有一个人使用工具工作,另一个人只能用手。

    结果如下:

    lisi starts a work with hand
    zhangsan starts a work with tool
    zhangsan finish a work and release tool
    lisi finish a work

    Java中的volatile关键字说,保证对变量的修改直接写入主存,线程读取变量的时候不会受到线程缓存的影响。轮询语句的条件变量就适合使用volatile关键字修饰    while( ! stop){}。 

    volatile并不保证关于变量的操作是原子性的。i++不具有原子性,AtomicInteger 提供了原子操作。

    import java.util.ArrayList;
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.atomic.AtomicInteger;
    
    class Room
    {
        //    public static volatile int personCount = 0;
        public static AtomicInteger inc = new AtomicInteger(0);
        public static void personEnter()
        {
            try{
                Thread.sleep(100);
            }catch (InterruptedException e){
    
            }finally {
    
            }
    //        Room.personCount = Room.personCount+1;
            inc.getAndIncrement();
        }
    }
    
    public class Test {
        public static void main(String[]args)
        {
            ArrayList<Thread> threadList = new ArrayList(10);
            for(int i=0; i< 10; i++){
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Room.personEnter();
                    }
                });
                threadList.add(thread);
            }
    
            for (int i =0;i<threadList.size(); i++){
                Thread thread = threadList.get(i);
                thread.start();
            }
    
            while (Thread.activeCount()>2)
                Thread.yield();
            System.out.println(Room.inc);
        }
    }
    

      

    使用volatile的结果是小于等于10的数,使用AtomicInteger结果一定是10

    ReentrantLock 可重入锁,可重入是针对线程而言的。

    import java.util.concurrent.locks.ReentrantLock;
    
    class Door implements Runnable
    {
        private ReentrantLock reentrantLock;
        private String name;
        public Door(ReentrantLock reentrantLock,String name)
        {
            this.reentrantLock = reentrantLock;
            this.name = name;
        }
    
        @Override
        public void run() {
            try{
                Thread.sleep(0);
            }catch (InterruptedException e){
    
            }finally {
    
            }
            this.reentrantLock.lock();
            System.out.println(this.name+" lock once");
            this.reentrantLock.lock();
            try{
                Thread.sleep(0);
            }catch (InterruptedException e){
    
            }finally {
    
            }
            System.out.println(this.name+" lock twice");
            System.out.println(this.name+" will unlock once");
            this.reentrantLock.unlock();
            System.out.println(this.name+" will unlock twice");
            this.reentrantLock.unlock();
        }
    }
    
    public class Test {
        public static void main(String[]args)
        {
            ReentrantLock reentrantLock = new ReentrantLock();
    
            Thread blackThread = new Thread(new Door(reentrantLock, "blackDoor"));
            Thread whiteThread = new Thread(new Door(reentrantLock, "whiteDoor"));
    
            blackThread.start();
            whiteThread.start();
        }
    }
    

     结果:

    blackDoor lock once
    blackDoor lock twice
    blackDoor will unlock once
    blackDoor will unlock twice
    whiteDoor lock once
    whiteDoor lock twice
    whiteDoor will unlock once
    whiteDoor will unlock twice

  • 相关阅读:
    CentOS yum 源的配置与使用
    CentOS 添加常用 yum 源
    给centOs添加epel源
    centos 推荐使用epel源
    如何在CentOS 5/6上安装EPEL 源
    为centos添加第三方源
    Linux远程桌面工具 -- NoMachine
    Redis windows版本的启停bat脚本命令
    Elasticsearch+Hbase实现海量数据秒回查询
    mysql 与elasticsearch实时同步常用插件及优缺点对比(ES与关系型数据库同步)
  • 原文地址:https://www.cnblogs.com/afraidToForget/p/10117340.html
Copyright © 2011-2022 走看看