线程的同步方法---单例模式的线程安全问题---线程同步的练习---死锁--生产者、消费者

五、同步方法:

1、同步方法:首先书写一个show()方法,用于将操作共享数据的代码块放入其中;其次在重写的run()方法中调用show()方法。

注意:同步方法只可以在实现线程(implements Runnable)的程序中使用;而继承(extends Thread)的线程中不可以,因为继承的方式中不能实现线程安全问题。

 

2、同步方法的可以用于的是—用实现的方式来实现线程。

class Window4 implements Runnable {

    int ticket = 100;



    public void run() {

        while(true) {

            show();

        }  

    }

    //用synchronized修饰方法,保证是线程同步。

    public synchronized void show() {//需要被同步的代码放到show()方法里

        if (ticket > 0) {

            try {

                Thread.currentThread().sleep(10);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            System.out.println(Thread.currentThread().getName() + "售票,票号为:" + ticket--);

        }

    }

}



public class TestWindow4 {

    public static void main(String[] args) {

        Window4 w=new Window4();

        Thread t1=new Thread(w);

        t1.setName("售票窗口1");

        Thread t2=new Thread(w);

        t2.setName("售票窗口2");

        Thread t3=new Thread(w);

        t3.setName("售票窗口3");



        t1.start();

        t2.start();

        t3.start();



    }

}

3、同步方法-不可以用于用继承的方式来实现线程的方法中。

 

五、互斥锁_单例之懒汉式的线程安全:

 

 

 

线程的同步的弊端:由于同一个时间只能由一个线程访问共享数据,效率变低了。


 

package com.atguigu.Thread2;



//关于懒汉式的线程安全问题:使用同步机制。

//对于一般的方法内,使用同步代码块,可以考虑使用this。

//对于静态方法而言,使用当前类本身充当锁。

class Singleton {

    private Singleton() {



    }



    private static Singleton instance = null;



    public static Singleton getInstance() {

        if (instance == null) {//四个人到达,如果此时instance为空,可以进入;如果后来的判断instance已经有了造好了,就不用等了,直接拿就行

            // Singleton.class返回的是一个对象

            synchronized (Singleton.class) { // 使用当前类本身来充当锁:Singleton.class

                if (instance == null) {

                   instance = new Singleton();

                }

            }

        }



        return instance;

    }

}



public class TestSingleton {



    public static void main(String[] args) {

        // TODO Auto-generated method stub

        Singleton s1 = Singleton.getInstance();

        Singleton s2 = Singleton.getInstance();

        System.out.println(s1 == s2);

        Class cla = Singleton.class;

    }



}

 

六、线程同步的练习:

package com.atguigu.Thread2;



class Account{

    double balance;//余额

    public Account() {

       

    }

    //存钱:使用synchronized保证了线程安全性

    public synchronized void deposit(double amt) {       

        balance+=amt;

        /*  try-catch的加的原因是使错误的效果更明显    */

        try {

            Thread.currentThread().sleep(10);

        } catch (Exception e) {

            // TODO: handle exception

        }

        System.out.println(Thread.currentThread().getName()+":"+balance);

    }

   

}



class Customer extends Thread{

    Account account;

   

    public Customer(Account account) {

        this.account=account;

    }

   

    public void run() {

        for(int i=0;i<3;i++) {

            account.deposit(1000);

        }

    }

}



public class TestAccount {

    public static void main(String[] args) {

        Account acct=new Account();

        Customer c1=new Customer(acct);

        Customer c2=new Customer(acct);

       

        c1.setName("甲");

        c2.setName("乙");

       

        c1.start();

        c2.start();

    }

}

七、线程的死锁问题:

吃饭的时候桌子上由一双筷子,两个人每个人抢到了一支,他们都不愿意放弃彼此的那一支筷子给对方,造成死锁状态,谁都吃不了饭。

package com.atguigu.Thread2;



//死锁的问题:处理线程同步时容易出现

public class TestDeadLock {

    static StringBuffer sb1=new StringBuffer();

    static StringBuffer sb2=new StringBuffer();

   

    public static void main(String[] args) {

        new Thread() {

            public void run() {

                synchronized(sb1) {//一号饭人握住sb1筷子

                   //try-catch部分,是休眠的时间,这段时间很有可能,sb2筷子被人抢走

                   try {

                       Thread.currentThread().sleep(10);

                   } catch (InterruptedException e) {

                       // TODO Auto-generated catch block

                       e.printStackTrace();

                   }

                   sb1.append("A");

                   synchronized(sb2) {

                       sb2.append("B");

                       System.out.println(sb1);

                       System.out.println(sb2);

                   }

                }

            }

        }.start();

       

       

        new Thread() {

            public void run() {

                synchronized(sb2) {//二号饭者握住sb2筷子

                   //try-catch部分二号饭者休眠,另一支筷子sb1已经被一号饭者拥有。

                   try {

                       Thread.currentThread().sleep(10);

                   } catch (InterruptedException e) {

                       // TODO Auto-generated catch block

                       e.printStackTrace();

                   }

                   sb1.append("c");

                   synchronized(sb1) {

                       sb2.append("d");

                       System.out.println(sb1);

                       System.out.println(sb2);

                   }

                }

            }

        }.start();

    }

}

 

八、线程的通信:

1实现二者的交替打印,使用线程的通信。

package com.atguigu.Thread2;



class Account{

    double balance;//余额

    public Account() {

       

    }

    //存钱:使用synchronized保证了线程安全性

    public synchronized void deposit(double amt) {       

        notify();

        balance+=amt;

        /*  try-catch的加的原因是使错误的效果更明显    */

        try {

            Thread.currentThread().sleep(10);

        } catch (Exception e) {

            // TODO: handle exception

        }

        System.out.println(Thread.currentThread().getName()+":"+balance);

        try {

            wait();

        } catch (InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

   

}



class Customer extends Thread{

    Account account;

   

    public Customer(Account account) {

        this.account=account;

    }

   

    public void run() {

        for(int i=0;i<3;i++) {

            account.deposit(1000);

        }

    }

}



public class TestAccount {

    public static void main(String[] args) {

        Account acct=new Account();

        Customer c1=new Customer(acct);

        Customer c2=new Customer(acct);

       

        c1.setName("甲");

        c2.setName("乙");

       

        c1.start();

        c2.start();

    }

}

九、生产者、消费者的问题

分析题目:

  1. 是否涉及到多线程的问题?是!生产者、消费者。
  2. 是否涉及到共享数据?有!考虑线程的安全。
  3. 此共享数据是谁?即为产品的数量。
  4. 是否涉及到线程的通信呢?存在着生产者与消费者的通信。


 

package guigu;

/*

 * 分析题目:

1、 是否涉及到多线程的问题?是!生产者、消费者。

2、 是否涉及到共享数据?有!考虑线程的安全。

3、 此共享数据是谁?即为产品的数量。

4、 是否涉及到线程的通信呢?存在着生产者与消费者的通信。



 * */

class Clerk{//店员

    int product;

    /*      有同步需要考虑产品的安全问题synchronized     */

    public synchronized void addProduct() {//生产产品

        if(product>=20) {

            try {

                wait();

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }else {

            product++;

            System.out.println(Thread.currentThread().getName()+":生产了第"+product+"个产品");

            notifyAll();//唤醒消费者

        }

    }

    public synchronized void consumeProduct(){//消费产品

        if(product<=0) {

            try {

                wait();

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }else {

            System.out.println(Thread.currentThread().getName()+":消费了第"+product+"个产品");

            product--;

            notifyAll();//唤醒生产者

        }

    }

}



class Producer implements Runnable{//生产者

    Clerk clerk;

    public Producer(Clerk clerk) {

        this.clerk=clerk;

    }

    public void run() {

        System.out.println("生产者开始生产产品");

        while(true) {

            try {

                Thread.currentThread().sleep(100);//让生产的节奏慢一点。

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            clerk.addProduct();

        }

    }

}



class Consumer implements Runnable{

    Clerk clerk;

    public Consumer(Clerk clerk) {

        this.clerk=clerk;

    }

    public void run() {

        System.out.println("消费者消费产品");

        while(true) {

            try {

                Thread.currentThread().sleep(1000);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            clerk.consumeProduct();

        }

    }

}

public class TestProduceConsume {

    public static void main(String[] args) {

        Clerk clerk=new Clerk();

        Producer p1=new Producer(clerk);

        Consumer c1=new Consumer(clerk);

        Thread t1=new Thread(p1);//一个生产者的线程

        Thread t3=new Thread(p1);//再造一个生产者的线程

        Thread t2=new Thread(c1);//一个消费者的线程

        t1.setName("生产者");

        t2.setName("消费者");

        t3.setName("生产者2");

       

        t1.start();

        t2.start();

        t3.start();

    }

   

}

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值