Java 多线程练习

11人阅读 评论(0) 收藏 举报
分类:
1.线程的同步和通信
       虚假唤醒:在increment和decrement里面需要用while 而不能用if,记住:在多线程中永远用while而不用if,因为if判断有可能这次通过,但是还有可能方法体内wait等待,所以必须用while。
class ShareData{
     private int number = 0;

     public synchronized void increment() throws InterruptedException{
           while(0 != number ){
               this.wait();
          }
          ++ number;
          System. out.println(Thread. currentThread().getName()+"\t"+ number);
           this.notifyAll();
     }

     public synchronized void decrement() throws InterruptedException{
           while(0 == number ){
               this.wait();
          }
          -- number;
          System. out.println(Thread. currentThread().getName()+"\t"+ number);
           this.notifyAll();
     }
}

/**
 * 题目:现在两个线程,可以操作同一个变量,实现一个线程对该变量加1,一个线程对该变量减1,实现交替,来10轮,变量初始值为零。
 * @author admin
 * 1      高内聚低耦合
 * 2 线程          操作               资源
 */
public class ThreadDemo2{
     public static void main(String[] args){
           final ShareData shareData = new ShareData();

           new Thread(new Runnable(){
               @Override
               public void run()
              {
                    for (int i = 0; i < 10; i++){
                         try{
                             shareData.increment();
                             Thread. sleep(200);
                        } catch (InterruptedException e){
                             e.printStackTrace();
                        }
                   }
              }
          }, "AA").start();

           new Thread(new Runnable()
          {
               @Override
               public void run()
              {
                    for (int i = 0; i < 10; i++)
                   {
                         try
                        {
                             shareData.decrement();
                             Thread. sleep(300);
                        } catch (InterruptedException e){
                             e.printStackTrace();
                        }
                   }
              }
          }, "BB").start();

           new Thread(new Runnable()
          {
               @Override
               public void run()
              {
                    for (int i = 0; i < 10; i++)
                   {
                         try
                        {
                             shareData.increment();
                             Thread. sleep(400);
                        } catch (InterruptedException e){
                             e.printStackTrace();
                        }
                   }
              }
          }, "CC").start();

           new Thread(new Runnable()
          {
               @Override
               public void run()
              {
                    for (int i = 0; i < 10; i++)
                   {
                         try
                        {
                             shareData.decrement();
                             Thread. sleep(500);
                        } catch (InterruptedException e){
                             e.printStackTrace();
                        }
                   }
              }
          }, "DD").start();
     }
}
2.加同步方法,加静态同步方法练习
    //1 标准访问,先打印苹果还是android
    //2 加入Thread.sleep(4000),先打印苹果还是android?
    //3 加入getHello(),先打印苹果还是hello?
    //4 有两部手机,先打印苹果还是android?
    //5 两个静态同步方法,有一部手机,先打印苹果还是android?
    //6 两个静态同步方法,有两部手机,先打印苹果还是android?
    //7 一个静态同步方法,一个普通同步方法,有一部手机,先打印苹果还是android?
    //先打印ios,因为在ios锁的是类对象本身 而android锁的是实例对象本身
    //8 一个静态同步方法,一个普通同步方法,有两部手机,先打印苹果还是android?
public class ThreadDemo3{
    public static void main(String[] args){
          final Phone phone = new Phone();
          final Phone phone2 = new Phone();

          new Thread(new Runnable(){
              @Override
              public void run(){
                   for (int i = 0; i < 1; i++){
                        try{
                             phone.getIOS ();
                       } catch (InterruptedException e){
                            e.printStackTrace();
                       }
                  }
             }
         }, "AA").start();

          new Thread(new Runnable(){
              @Override
              public void run(){
                   for (int i = 0; i < 1; i++){
                        try
                       {
                             //phone.getAndroid();
                             //phone.getHello();
                            phone2.getAndroid();
                       } catch (InterruptedException e){
                            e.printStackTrace();
                       }
                  }
             }
         }, "BB").start();
    }
}
class Phone{
    public static synchronized void getIOS() throws InterruptedException{
         Thread.sleep(4000);
         System.out.println("-----getIOS" );
    }

    public synchronized void getAndroid() throws InterruptedException{
         System.out.println("-----getAndroid" );
    }

    public void getHello() throws InterruptedException{
         System.out.println("-----getHello" );
    }
}
结论:
      一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
     锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
     加个普通方法后发现和同步锁无关
     换成两个对象后,不是同一把锁了,情况立刻变化。
     都换成静态同步方法后,情况又变化
     所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
     所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!

3.考察两个线程相互交换:在main方法中创建并启动两个线程。第一个线程循环随机打印100以内的整数,直到第二个线程从键盘读取了“Q”命令。
public class HelloThread4 implements Runnable{

     private static boolean flag = true;

     @Override
     public void run() {
         while(flag){
              int num = (int)(Math.random() * 101);
              System.out.println(num);
         }
     }

     public static void setFlag(){
         flag = false;
     }

}
public class HelloThread5 implements Runnable{
     @Override
     public void run() {
         Scanner scan = new Scanner(System.in);
         while(scan.hasNext()){
              String str = scan.next();
              if(str.equalsIgnoreCase("Q")){
                  HelloThread4.setFlag();
                   System.out.println("---------------------------------");
              }
         }
     }
}
/*
 * 在main方法中创建并启动两个线程。第一个线程循环随机打印100以内的整数,直到第二个线程从键盘读取了“Q”命令。
 */
public class TestThread2 {

     public static void main(String[] args) {
         HelloThread4 ht4 = new HelloThread4();
         Thread t1 = new Thread(ht4);
         t1.start();

         HelloThread5 ht5 = new HelloThread5();
         Thread t2 = new Thread(ht5);
         t2.start();
     }

}


4.考察线程基本使用:编写程序,在main方法中创建一个线程。线程每隔一定时间(200ms以内的随机时间)产生一个0-100之间的随机整数,打印后将该整数放到集合中; 共产生100个整数,全部产生后,睡眠30秒,然后将集合内容打印输出; 在main线程中,唤醒上述睡眠的线程,使其尽快打印集合内容。
public class HelloThread6 implements Runnable{

     List<Integer> list = new ArrayList<Integer>();

     static boolean flag = false;

     @Override
     public void run() {
         for (int i = 0; i < 100; i++) {
              int millis = (int)(Math.random() * 200);
              try {
                  Thread.sleep(millis);
              } catch (InterruptedException e) {
              }
              int num = (int)(Math.random() * 101);
              System.out.println(num);
              list.add(num);
         }

         //-------------------
         flag = true;

         try {
              Thread.sleep(30000);
         } catch (InterruptedException e) {
         }
         Iterator<Integer> it = list.iterator();
         while(it.hasNext()){
              System.out.println("--" + it.next());
         }
     }

}
public class TestThread3 {

     public static void main(String[] args) {
         HelloThread6 ht6 = new HelloThread6();
         Thread t6 = new Thread(ht6);
         t6.start();

         while(t6.isAlive()){
              if(HelloThread6.flag){
                  t6.interrupt();
              }
         }
     }

}

5.线程同步解决线程单利设计模式的懒汉式线程安全问题
public class TestSingleton {
}

//懒汉式
class Singleton{
    //1. 私有化构造器
    private Singleton(){}

    //2. 类的内部创建对象
    private static Singleton instance = null;

    public static Singleton getInstance(){

        if(instance == null){//为了减少判断,可用于提高效率
            synchronized (Singleton.class) {//Class
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
查看评论

java学习之路 之 多线程练习题

package com.atguigu.javase.thread; /** * 创建并启动一个线程的方法 * 1) 实现接口的方式 * 1) 写一个具体类, 实现Runnable接...
  • OnlyLove_longshao
  • OnlyLove_longshao
  • 2016-08-28 10:37:51
  • 3959

Java多线程之键盘操作练习

Java多线程之键盘操作练习GiveLetterThread.javapackage gxy.thread1;public class GiveLetterThread extends Thread ...
  • mhtqq809201
  • mhtqq809201
  • 2016-06-22 16:56:36
  • 1121

Java多线程练习题

  • 2008年11月21日 09:00
  • 39KB
  • 下载

JAVA多线程练习题答案。

  • 2011年04月13日 23:10
  • 82KB
  • 下载

简单的 java 多线程编程练习。

9.     Java多线程编程题: 启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. ...
  • u010484308
  • u010484308
  • 2014-12-04 16:49:20
  • 2053

java基础多线程练习题(1)

  • 2017年08月08日 15:26
  • 7KB
  • 下载

Java多线程经典例题一

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下...
  • qq_34129814
  • qq_34129814
  • 2017-04-14 16:14:32
  • 814

JAVA编程思想第四版-多线程的练习答案之练习10

package exercise.exercise10; import java.util.ArrayList; import java.util.concurrent.Callable; impo...
  • ltp2010
  • ltp2010
  • 2013-10-21 00:19:30
  • 968

一道经典的Java多线程编程题

问题描述 启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. 接着再由线程1打印16,17,18...
  • u014039577
  • u014039577
  • 2015-09-21 11:10:34
  • 5321

java基础之多线程的练习题

题目如下: 某公司组织年会,会议入场时有两个入口,在入场时每位员工都能获取一张双色球彩票,假设公司有100个员工,利用多线程模拟年会入场过程, 并分别统计每个入口入场的人数,以及每个员工拿到的彩票...
  • u014028392
  • u014028392
  • 2017-08-08 15:11:19
  • 867
    个人资料
    持之以恒
    等级:
    访问量: 10万+
    积分: 3226
    排名: 1万+
    最新评论