线程(5)--关于同步、死锁

一.关于同步

1.什么情况下需要同步

  • 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.

  • 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
    2.同步代码块

  • 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块

  • 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的
    3.非静态方法的锁对象是: this
    4.静态方法的锁对象是:字节码对象,也就是这个方法对应所在的那个类的.class对象,

package com.fenqing.duoxiancheng;

public class d11_Synchronized {

    public static void main(String[] args) {
        final Printer p=new Printer();
        new Thread(){
            public void run(){
                while(true){
                    p.print1();
                }
            }
        }.start();
        new Thread(){
            public void run(){
                while(true){
                    p.print2();
                }
            }
        }.start();
    }

}
class Printer {
    static demo d = new demo();
    public static void print1() {       //方法是static,所以锁对象也要用static修饰
        //synchronized(new demo()){     //不能用匿名对象,因为匿名对象不是同一个对象,也就是说不是同一把锁
        synchronized(d){                //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,
            System.out.print("计");      
            System.out.print("算");
            System.out.print("机");
            System.out.print("\r\n");
        }
    }

    public static void print2() {   
        synchronized(d){    
            System.out.print("软");
            System.out.print("件");
            System.out.print("工");
            System.out.print("程");
            System.out.print("\r\n");
        }
    }

    public synchronized void print3(){  //定义同步方法
        System.out.print("专");
        System.out.print("业");
        System.out.print("\r\n");
    }
}

class demo{

}

线程安全性

  • 多线程并发操作同一数据时, 就有可能出现线程安全问题
  • 使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作

关于同步的练习

四个窗口出售100张票的问题。

1,用Thread()的构造实现

package com.fenqing.duoxiancheng;

public class d12_sell {

    public static void main(String[] args) {
        TicketsSeller t1 = new TicketsSeller();
        TicketsSeller t2 = new TicketsSeller();
        TicketsSeller t3 = new TicketsSeller();
        TicketsSeller t4 = new TicketsSeller();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t4.setName("窗口4");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}
class TicketsSeller extends Thread {
    private static int tickets = 100;
    static Object obj = new Object();
    public TicketsSeller() {
        super();

    }
    public TicketsSeller(String name) {
        super(name);
    }
    public void run() {
        while(true) {
            synchronized(obj) {
                if(tickets <= 0) 
                    break;
                try {
                    Thread.sleep(10);//线程1睡,线程2睡,线程3睡,线程4睡
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
                System.out.println(getName() + "...这是第" + tickets-- + "号票");
            }
        }
    }
}

2.用Runnable实现

package com.fenqing.duoxiancheng;

public class d13_sell {

    public static void main(String[] args) {
        Ticket t=new Ticket();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }

}
class Ticket implements Runnable {
    private  int tickets = 100;
    public void run() {
        while(true) {
            synchronized(Ticket.class) {
                if(tickets <= 0) 
                    break;
                try {
                    Thread.sleep(10);//线程1睡,线程2睡,线程3睡,线程4睡
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"...这是第" + tickets-- + "号票");
            }
        }
    }
}

死锁——哲学家进餐的问题

  • 多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁。

不清楚这个问题的可以看看哲学家就餐问题简介

package com.fenqing.duoxiancheng;

public class d14_deathLock {

    private static String s1 = "筷子左";       //定义两个变量
    private static String s2 = "筷子右";

    public static void main(String[] args) {
        new Thread() {
            public void run() {
                while(true) {
                    synchronized(s1) {
                        System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
                        synchronized(s2) {
                            System.out.println(getName() + "...拿到" + s2 + "开吃");
                        }
                    }
                }
            }
        }.start();

        new Thread() {
            public void run() {
                while(true) {
                    synchronized(s2) {
                        System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
                        synchronized(s1) {
                            System.out.println(getName() + "...拿到" + s1 + "开吃");
                        }
                    }
                }
            }
        }.start();
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章