zoukankan      html  css  js  c++  java
  • 多线程——线程安全

    线程安全
    如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
    线程同步(线程安全处理Synchronized)
    同步代码块
    //同步代码块
    public class MyTicket3 implements Runnable{
        private int ticket=100;
        Object obj=new Object();//锁对象
        public void run() {
            while(true){
                synchronized (obj) {//扩起可能产生问题的代码块
                    if(ticket>0){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"卖第"+ticket--+"张票");
                    } 
                }
            }
        }
    }
    同步方法
    //同步方法   锁对象:this
    //静态同步方法  锁对象:MyTicket2.class
    //加了同步安全  但是运行速度会下降    StringBuffer就是加了同步   StringBuilder没加
    public class MyTicket2 implements Runnable{
        private static int ticket=100;
        public static synchronized void method(){
            if(ticket>0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖第"+ticket--+"张票");
            } 
        }
        public void run() {
            while(true){
                method();
            }
        }
    }
    Lock接口
    Lock接口中的常用方法
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //Lock接口
    public class MyTicket implements Runnable{
        private int ticket=100;
        private Lock lock=new ReentrantLock();//创建Lock接口实现类对象
        public void run() {
            while(true){
                lock.lock();//获取锁
                    if(ticket>0){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"卖第"+ticket--+"张票");
                    }
                lock.unlock();//释放锁    
            }
        }
    }
    
    public class SaleTicket {
        public static void main(String[] args) {
            MyTicket mt=new MyTicket();
            //创建线程
            Thread t0=new Thread(mt);
            Thread t1=new Thread(mt);
            Thread t2=new Thread(mt);
            //开启线程
            t0.start();
            t1.start();
            t2.start();
        }
    }
    死锁
    同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。
    
    public class LockA {
        private LockA(){}
        public final static LockA locka=new LockA();
    }
    public class LockB {
        private LockB(){}
        public final static LockB lockb=new LockB();
    }
    public class DeadLock implements Runnable{
        private int i=0;
        public void run() {
            while(true){
                if(i%2==0){
                    synchronized (LockA.locka) {
                        System.out.println("if-locka");
                        synchronized (LockB.lockb) {
                            System.out.println("if-lockb");
                        }
                    }
                }else{
                    synchronized (LockB.lockb) {
                        System.out.println("else-lockb");
                        synchronized (LockA.locka) {
                            System.out.println("else-locka");
                        }
                    }
                }
                i++;
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            DeadLock dl=new DeadLock();
            Thread t0=new Thread(dl);
            Thread t1=new Thread(dl);
            t0.start();
            t1.start();
        }
    }
    等待唤醒机制
    等待唤醒机制所涉及到的方法:
    wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
    notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
    notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
    示例
    1.当input发现Resource中没有数据时,开始输入,输入完成后,叫output来输出。如果发现有数据,就wait();
    2.当output发现Resource中没有数据时,就wait() ;当发现有数据时,就输出,然后,叫醒input来输入数据。
    public class Resource {
        public String name;
        public int age;
        //添加标记:true:赋值完成  false:输出完成
        public boolean flag=false;
    }
    public class Input implements Runnable{
        //对Resource进行赋值
        private Resource r;
        public Input(){}
        public Input(Resource r){
            this.r=r;
        }
        public void run() {
            int i=0;
            while(true){
                //添加同步代码块
                synchronized (r) {
                    //判断标记
                    if(r.flag){
                        try {
                            r.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if(i%2==0){
                        r.name="张三";
                        r.age=18;
                    }else{
                        r.name="李四";
                        r.age=81;
                    }
                    r.flag=true;
                    r.notify();
                }
                i++;
            }
        }
    }
    public class Output implements Runnable{
        private Resource r;
        public Output(){}
        public Output(Resource r){
            this.r=r;
        }
        public void run() {
            //对Resourse进行输出
            while(true){
                synchronized (r) {
                    //判断标记
                    if(!r.flag){
                        try {
                            r.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(r.name+" "+r.age);
                    //改标记  唤醒input
                    r.flag=false;
                    r.notify();
                }
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            Resource r=new Resource();
            Input in=new Input(r);
            Output out=new Output(r);
            Thread tin=new Thread(in);
            Thread tout=new Thread(out);
            tin.start();
            tout.start();
        }
    }
     
  • 相关阅读:
    使用JS对字符串进行MD5加密
    awk 控制语句if-else
    nginx日志切割
    Nginx日志监控工具
    运维小工具
    shell脚本2
    nginx优化方案
    centos7修复grub2
    Centos7的引导顺序
    如何同时运行两个tomcat?
  • 原文地址:https://www.cnblogs.com/zhaotao11/p/10250507.html
Copyright © 2011-2022 走看看