22 - 线程安全 死锁 同步锁

1. 同步锁
    多个线程想保证线程安全,必须要使用同一个锁对象
    
    同步代码块
         synchronized (锁对象){
            可能产生线程安全问题的代码
            }
            同步代码块的锁对象可以是任意的对象

    同步方法
        public synchronized void method()
              可能产生线程安全问题的代码
        }
            同步方法中的锁对象是 this

    静态同步方法
        public synchronized void method()
                      可能产生线程安全问题的代码
        }
        静态同步方法中的锁对象是 类名.class

2. 多线程有几种实现方案,分别是哪几种?
    a, 继承Thread类
    b, 实现Runnable接口
    c, 通过线程池,实现Callable接口

3. 同步有几种方式,分别是什么?
    a,同步代码块
    b,同步方法
        静态同步方法

4. 启动一个线程是run()还是start()?它们的区别?
        启动一个线程是start()
        区别:
            start: 启动线程,并调用线程中的run()方法
            run  : 执行该线程对象要执行的任务

5. sleep()和wait()方法的区别
        sleep: 不释放锁对象, 释放CPU使用权
                在休眠的时间内,不能唤醒
        wait(): 释放锁对象, 释放CPU使用权
                在等待的时间内,能唤醒

6. 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
        锁对象可以是任意类型的对象

 

package cn.itcast.demo;
/*
 *  通过线程休眠,出现安全问题
 *  解决安全问题,Java程序,提供技术,同步技术
 *  公式:
 *    synchronized(任意对象){
 *      线程要操作的共享数据
 *    }
 *    同步代码块
 */
public class Tickets implements Runnable{
    
    //定义出售的票源
    private int ticket = 100;
    private Object obj = new Object();
    
    public void run(){
        while(true){
            //线程共享数据,保证安全,加入同步代码块
            synchronized(obj){
            //对票数判断,大于0,可以出售,变量--操作
                if( ticket > 0){
                    try{
                       Thread.sleep(10);
                    }catch(Exception ex){}
                    System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
                }
            }
        }
    }
}
package cn.itcast.demo;
/*
 * 多线程并发访问同一个数据资源
 * 3个线程,对一个票资源,出售
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //创建Runnable接口实现类对象
        Tickets t = new Tickets();
        //创建3个Thread类对象,传递Runnable接口实现类
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        
        t0.start();t1.start();t2.start();
        
    }
}

-----

package cn.itcast.demo1;
/*
 *  采用同步方法形式,解决线程的安全问题
 *  好处: 代码简洁
 *  将线程共享数据,和同步,抽取到一个方法中
 *  在方法的声明上,加入同步关键字
 *  
 *  问题:
 *    同步方法有锁吗,肯定有,同步方法中的对象锁,是本类对象引用 this
 *    如果方法是静态的呢,同步有锁吗,绝对不是this
 *    锁是本类自己.class 属性
 *    静态方法,同步锁,是本类类名.class属性
 */
public class Tickets implements Runnable{

    //定义出售的票源
    private  int ticket = 100;
    
    public void run(){
        while(true){
            payTicket();
        }
    }
    
    public  synchronized void payTicket(){    
            if( ticket > 0){
                try{
                   Thread.sleep(10);
                }catch(Exception ex){}
                System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
            }
        
    }
}
package cn.itcast.demo1;
/*
 * 多线程并发访问同一个数据资源
 * 3个线程,对一个票资源,出售
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //创建Runnable接口实现类对象
        Tickets t = new Tickets();
        //创建3个Thread类对象,传递Runnable接口实现类
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        
        t0.start();t1.start();t2.start();
        
    }
}

----

package cn.itcast.demo2;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
 *  使用JDK1.5 的接口Lock,替换同步代码块,实现线程的安全性
 *  Lock接口方法:
 *     lock() 获取锁
 *     unlock()释放锁
 *  实现类ReentrantLock
 */
public class Tickets implements Runnable{
    
    //定义出售的票源
    private int ticket = 100;
    //在类的成员位置,创建Lock接口的实现类对象
    private Lock lock = new ReentrantLock();
    
    public void run(){
        while(true){
            //调用Lock接口方法lock获取锁
            lock.lock();
            //对票数判断,大于0,可以出售,变量--操作
                if( ticket > 0){
                    try{
                       Thread.sleep(10);
                       System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
                    }catch(Exception ex){
                        
                    }finally{
                        //释放锁,调用Lock接口方法unlock
                        lock.unlock();
                    }
                }
    
            
        }
    }
}
package cn.itcast.demo2;
/*
 * 多线程并发访问同一个数据资源
 * 3个线程,对一个票资源,出售
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //创建Runnable接口实现类对象
        Tickets t = new Tickets();
        //创建3个Thread类对象,传递Runnable接口实现类
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        
        t0.start();t1.start();t2.start();
        
    }
}

===

package cn.itcast.demo3;

public class LockA {
    private LockA(){}
    
    public  static final LockA locka = new LockA();
}
package cn.itcast.demo3;

public class LockB {
    private LockB(){}
    
    public static final LockB lockb = new LockB();
}
package cn.itcast.demo3;

public class DeadLockDemo {
    public static void main(String[] args) {
        DeadLock dead = new DeadLock();
        Thread t0 = new Thread(dead);
        Thread t1 = new Thread(dead);
        t0.start();
        t1.start();
    }
}
package cn.itcast.demo3;

public class DeadLock implements Runnable{
    private int i = 0;
    public void run(){
        while(true){
            if(i%2==0){
                //先进入A同步,再进入B同步
                synchronized(LockA.locka){
                    System.out.println("if...locka");
                    synchronized(LockB.lockb){
                        System.out.println("if...lockb");
                    }
                }
            }else{
                //先进入B同步,再进入A同步
                synchronized(LockB.lockb){
                    System.out.println("else...lockb");
                    synchronized(LockA.locka){
                        System.out.println("else...locka");
                    }
                }
            }
            i++;
        }
    }
}

====

package cn.itcast.demo4;
/*
 *  开启输入线程和输出线程,实现赋值和打印值
 */
public class ThreadDemo{
    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();
    }
}
package cn.itcast.demo4;
/*
 *  定义资源类,有2个成员变量
 *  name,sex
 *  同时有2个线程,对资源中的变量操作
 *  1个对name,age赋值
 *  2个对name,age做变量的输出打印
 */
public class Resource {
    public String name;
    public String sex;
    public boolean flag = false;
}
package cn.itcast.demo4;
/*
 *  输出线程,对资源对象Resource中成员变量,输出值
 */
public class Output implements Runnable {
    private Resource r ;
    
    public Output(Resource r){
        this.r = r;
    }
    public void run() {
        while(true){
          synchronized(r){    
              //判断标记,是false,等待
            if(!r.flag){
                try{r.wait();}catch(Exception ex){}
            }
            System.out.println(r.name+".."+r.sex);
            //标记改成false,唤醒对方线程
            r.flag = false;
            r.notify();
          }
        }
    }

}
package cn.itcast.demo4;
/*
 *  输入的线程,对资源对象Resource中成员变量赋值
 *  一次赋值 张三,男
 *  下一次赋值 lisi,nv
 */
public class Input implements Runnable {
    private Resource r ;
    
    public Input(Resource r){
        this.r = r;
    }
    
    public void run() {
        int i = 0 ;
        while(true){
          synchronized(r){
              //标记是true,等待
                if(r.flag){
                    try{r.wait();}catch(Exception ex){}
                }
              
                if(i%2==0){
                    r.name = "张三";
                    r.sex = "男";
                }else{
                    r.name = "lisi";
                    r.sex = "nv";
                }
                //将对方线程唤醒,标记改为true
                r.flag = true;
                r.notify();
          }
            i++;
        }
    }

}
posted @ 2019-07-12 16:34  Alice的小屋  阅读(161)  评论(0编辑  收藏  举报