张孝祥java.concurrent线程并发学习笔记 - 传统线程回顾

来源:互联网 发布:linux 查看挂起进程 编辑:程序博客网 时间:2024/06/10 03:35

线程的定义:

每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。

线程的状态:

1、 new 新建 

2、 Runnable 可以运行(就绪) 

3、 Running 运行(正在运行) 

4、 Block 阻塞  挂起 

5、 Dead 死亡

线程之间的转换关系:

如何新建并启动线程:

Thread thread = new Thread(){//Thread是线程类,new Thread()即是新建了一个线程。@Overridepublic void run() {//线程当然要运行代码,重写run方法即可加入此线程的运行代码。while(true){try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("1:" + Thread.currentThread().getName());System.out.println("2:" + this.getName());}}};thread.start();//启动线程,将线程从新建状态变为可运行状态,将等待CPU调度。Thread thread2 = new Thread(new Runnable(){//新建线程也可以使用Runnable对象,重新Runnable对象的run方法。@Overridepublic void run() {//Thread类的run方法会调用传递的Runnable对象的run方法,所以这里重写Runable对象的run方法。while(true){try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("1:" + Thread.currentThread().getName());}}});thread2.start();
这两种方式没有什么区别,看个人爱好使用。

推荐第二种方法,因为这更加面向对象,它将线程要运行的代码进行了封装。


如何实现线程的互斥:

线程互斥是指对于共享的资源,在各线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。
java中的线程互斥使用synchronized关键字,synchronized可以声明一个代码块,可以声明一个方法(可以是静态方法)。
例:
static class Outputer{public void output(String name){int len = name.length();synchronized (Outputer.class) //声明代码块,使用Outputer.class作为锁。{for(int i=0;i<len;i++){System.out.print(name.charAt(i));}System.out.println();}}public synchronized void output2(String name){ //声明方法,将使用this作为锁。int len = name.length();for(int i=0;i<len;i++){System.out.print(name.charAt(i));}System.out.println();}public static synchronized void output3(String name){//声明静态方法,将使用Outputer.class作为锁。int len = name.length();for(int i=0;i<len;i++){System.out.print(name.charAt(i));}System.out.println();}}
经验:设计线程互斥代码,需要考虑互斥锁和线程之间的共享数据,设计代码时尽量保证互斥锁、共享数据、synchronized声明归在同一个类的身上,这样既便于维护,同时保证了良好的高内聚,外部调用者不必关心同步控制的问题。


线程协同的通信:

线程互斥本身可以理解为线程通信的一种方式,是一个线程A说“我进去了,等我出来后你们再进”。其它线程就在外面等待,直到看见A出来,其它线程才会进去并且说“我也进去了,等我出来后你们再进”。
但是有这样一种场景,一个线程A在不停的生产面包,放进面包箱里,另一个线程B在不停的从面包箱里取出面包,然后吃掉。当面包箱满的时候,线程A应该暂停,当B吃掉面包时,面包箱变得不满,应该通知线程A继续生产,这就需要线程之间的协同通信。
java的Object对象提供了两个方法用于实现线程协同通信,wait();和notify();。
wait():在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待,并释放当前互斥锁。
notify() :唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个wait 方法,在对象的监视器上等待。 
以下是一段参考代码,实现了两个线程的交替运行:
import java.util.concurrent.atomic.AtomicInteger;public class TraditionalThreadCommunication {/** * @param args */public static void main(String[] args) {final Business business = new Business();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){business.sub(i);}}}).start();for(int i=1;i<=50;i++){business.main(i);}}}  class Business {  private boolean bShouldSub = true;//是否可以由sub运行。  public synchronized void sub(int i){  while(!bShouldSub){  try {this.wait();//不该sub方法运行时,让sub进入等待。} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}  }for(int j=1;j<=10;j++){System.out.println("sub thread sequence of " + j + ",loop of " + i);}  bShouldSub = false;  this.notify();//sub方法运行完毕后,通知main运行。  }    public synchronized void main(int i){  while(bShouldSub){  try {this.wait();//不该main运行时,让main进入等待。} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}  }for(int j=1;j<=100;j++){System.out.println("main thread sequence of " + j + ",loop of " + i);}bShouldSub = true;this.notify();//main方法运行完毕后,通知sub运行。  }  }





原创粉丝点击