Java SE 09 线程

1.    线程的基本概念

2.线程的创建和启动

优先使用接口而不是继承

线程启动(调用Thread Start()方法):

交替输出

方法调用:

被调用的方法执行完再执行main函数的方法

package com.thread;
/**
 * 方法一
 * */
public class TestThread {
       public static void main(String[] args) {
              //方法一
              Runner1 r1 = new Runner1();
              Thread t = new Thread(r1);
              t.run();     //执行完调用的方法再继续执行,r1、r2是两个子线程,和main方法后面的代码交替执行
              t.start();
              //方法二
              Runner2 r2 = new Runner2();
              r2.start();
             
              for(int i=0;i<100;i++)
                     System.out.println("main:"+i);
       }
 
}
 
class Runner1 implements Runnable{
 
       @Override
       public void run() {
              for(int i=0;i<100;i++)
                     System.out.println("Runner1:"+i);
       }
      
}
 
class Runner2 extends Thread{
       public void run() {
              for(int i=0;i<100;i++)
                     System.out.println("Runner2:"+i);
       }
}
/*
 * 先执行调用的r1的run()方法进行输出
 * 然后r1线程、r2线程、main线程轮流交替执行(输出)
 * */

3.线程的状态控制

Join相当于方法调用

4.线程同步

       线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作,而其他线程又处于等待状态。

当一个线程在使用加锁的方法时,其它线程仍可以访问这个这个对象的其他未加锁方法。synchronized只锁定对象,每个对象只有一个锁(lock)与之相关联,因此同一个对象的不同加锁方法执行顺序有先后。访问同一个资源的所有方法都要仔细考虑是否加锁。

 

package com.thread;
/*
 * 两个线程访问同一个timer对象
 * */
public class TestSync implements Runnable{
 
       Timer timer = new Timer();
       public static void main(String[] args) {
              TestSync test = new TestSync();
              Thread t1 = new Thread(test);
              Thread t2 = new Thread(test);
              t1.setName("t1");
              t2.setName("t2");
              t1.start();
              t2.start();
       }
       @Override
       public void run() {
              timer.add(Thread.currentThread().getName());
       }
 
}
 
class Timer{
       private static int num = 0;
       public synchronized void add(String name) {  //对当前对象加锁
              //synchronized(this) {//另一种加锁方式
              num++;
              try {
                     Thread.sleep(1);      //访问该资源的线程休眠一毫秒
              } catch (InterruptedException e) {
                     e.printStackTrace();
              }
              System.out.println(name+",你是第"+num+"个使用timer的线程");
              //}
       }
}
/*
不加锁时
运行可能的结果一(t1 num++后休眠,[t2 num++、休眠、输出],然后t1输出)
t2,你是第2个使用timer的线程
t1,你是第2个使用timer的线程
或结果二
t1,你是第1个使用timer的线程
t2,你是第1个使用timer的线程
或...
 
加锁时
t1,你是第1个使用timer的线程
t2,你是第2个使用timer的线程
 */

死锁

package com.thread;
 
public class TestDeadLock implements Runnable{
       //用以区分,一个线程类模拟两个线程
       public int flag = 0; 
       //要访问的两个对象(静态公共资源)
       static Object o1 = new Object(); 
       static Object o2 = new Object();
      
       public void run() {
           System.out.println("flag="+flag);
           //线程1对o1加锁,只要再对o2加锁即可完成进程
           if (flag == 1) {
                  synchronized(o1) {
                         try {
                                   Thread.sleep(500);
                            } catch (InterruptedException e) {
                                   e.printStackTrace();
                            }
                         synchronized(o2) {
                                System.out.println("1");
                         }
                  }
           }
           //线程2对o2加锁,只要再对o1加锁即可完成进程
           if (flag == 0) {
                  synchronized(o2) {
                         try {
                                   Thread.sleep(500);
                            } catch (InterruptedException e) {
                                   e.printStackTrace();
                            }
                         synchronized(o1) {
                                System.out.println("0");
                         }
                  }
           }
       }
      
       public static void main(String[] args) {
              TestDeadLock td1 = new TestDeadLock();
              TestDeadLock td2 = new TestDeadLock();
              td1.flag=1;
              td2.flag=0;
              Thread t1 = new Thread(td1);
              Thread t2 = new Thread(td2);
              //启动两个线程
              t1.start();
              t2.start();
       }
}
/**
flag=1
flag=0
//程序卡住
*/

5.生产者消费者问题

多个线程对同一资源进行生产和消费

package com.thread;
/**
 * 生产者消费者问题
 *1.往框内放的push()方法要加锁
 *2.往筐外取的pop()方法要加锁
 *3.食物筐满则停止生产,消费出位置再生产
 *4.食物筐空则停止消费,生产出食物载消费
 */
public class ProducerConsumer {
 
       public static void main(String[] args) {
              SyncStack ss = new SyncStack();
              Producer p = new Producer(ss);
              Consumer c = new Consumer(ss);
              new Thread(p).start();
              new Thread(c).start();
 
       }
 
}
/**
 * 面包
 * */
class Bread{
       int id;
       Bread(int id){
              this.id = id;
       }
       @Override
       public String toString() {
              return "Bread [id=" + id + "]";
       }
}
/**
 * 面包筐
 * */
class SyncStack{
      
       Bread[] breads = new Bread[6];
       int index = 0;
      
       public synchronized void push(Bread bread) {
              while (index == breads.length) {     //面包筐生产满了
                     try {
                            //访问当前加锁对象的进程进入wait状态(object对象的方法)
                            this.wait();
                     } catch (InterruptedException e) {
                            e.printStackTrace();
                     }
              }
              //叫醒正在当前对象内wait的进程(object对象的方法)
              this.notifyAll();
              breads[index] = bread;         //不加锁这里容易出问题     
              index++;
       }
      
       public synchronized Bread pop() {
              while (index == 0) {       //面包筐消费空了
                     try {
                            this.wait();;
                     } catch (InterruptedException e) {
                            e.printStackTrace();
                     }
              }
              this.notifyAll();
              index--;                 //不加锁这里容易出问题
              return breads[index];
       }
}
/**
 * 生产者
 * */
class Producer implements Runnable{
       SyncStack ss = null;
       Producer(SyncStack ss){
              this.ss = ss;
       }
       @Override
       public void run() {
              for(int i=1;i<=20;i++) {
                     Bread bread = new Bread(i);
                     ss.push(bread);
                     System.out.println("生产"+bread);
                     try {
                            Thread.sleep(1000);
                     } catch (InterruptedException e) {
                            e.printStackTrace();
                     }
              }
       }
}
/**
 * 消费者
 * */
class Consumer implements Runnable{
       SyncStack ss = null;
       Consumer(SyncStack ss){
              this.ss = ss;
       }
       @Override
       public void run() {
              for(int i=1;i<=20;i++) {
                     Bread bread = ss.pop();
                     System.out.println("消费"+bread);
                     try {
                            Thread.sleep(2000);
                     } catch (InterruptedException e) {
                            e.printStackTrace();
                     }
              }
       }
}
/*
生产Bread [id=1]
消费Bread [id=1]
生产Bread [id=2]
消费Bread [id=3]
生产Bread [id=3]
生产Bread [id=4]
生产Bread [id=5]
消费Bread [id=4]
生产Bread [id=6]
消费Bread [id=7]
生产Bread [id=7]
生产Bread [id=8]
消费Bread [id=8]
生产Bread [id=9]
生产Bread [id=10]
消费Bread [id=10]
生产Bread [id=11]
生产Bread [id=12]
消费Bread [id=12]
生产Bread [id=13]
消费Bread [id=13]
生产Bread [id=14]
消费Bread [id=14]
生产Bread [id=15]
消费Bread [id=15]
生产Bread [id=16]
消费Bread [id=16]
生产Bread [id=17]
消费Bread [id=17]
生产Bread [id=18]
消费Bread [id=18]
生产Bread [id=19]
消费Bread [id=19]
生产Bread [id=20]
消费Bread [id=20]
消费Bread [id=11]
消费Bread [id=9]
消费Bread [id=6]
消费Bread [id=5]
消费Bread [id=2]
 */

6.总结

wait sleep 区别

1)所属类不同

wait()   java.lang.object

sleep()  java.lang.Thread

2wait 时别的线程可以访问锁定对象(调用wait方法必须锁定该对象)

sleep时别的线程不可以访问锁定对象

 

线程/进程的概念

创建和启动线程的方法

sleep

join

yield

synchronized

wait

notify/notifyAll

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值