多线程——线程安全

线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程同步(线程安全处理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();
    }
}

 

 

 

posted @ 2019-01-10 16:00  帅涛  阅读(134)  评论(0编辑  收藏  举报