J2EE-线程

来源:互联网 发布:网络yy语音授课是什么 编辑:程序博客网 时间:2024/05/17 23:32

1、什么是线程

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

2、线程状态(图)

流程图

  1. 调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。
  2. 调用wait(),使该线程处于等待池(wait blocked pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),释放同步锁使线程回到可运行状态(Runnable)
  3. 对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。
    此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。

3、 创建线程

(1)方式一:创建Thread子类的一个实例并重写run方法
//创建线程子类,重新run方法public class MyThread extends Thread {   public void run(){     System.out.println("MyThread running");   }}//创建线程并执行MyThread myThread = new MyThread();myTread.start();

一旦线程启动后start方法就会立即返回,而不会等待到run方法执行完毕才返回。就好像run方法是在另外一个cpu上执行一样。当run方法执行后,将会打印出字符串MyThread running。

(2)方式二:创建一个Thread的匿名子类
Thread thread = new Thread(){   public void run(){     System.out.println("Thread Running");   }};thread.start();

当新的线程的run方法执行以后,计算机将会打印出字符串”Thread Running”。

(3)方式三:实现Runnable接口

新建一个实现了java.lang.Runnable接口的类的实例,实例中的方法可以被线程调用。

public class MyRunnable implements Runnable {   public void run(){    System.out.println("MyRunnable running");   }}

为了使线程能够执行run()方法,需要在Thread类的构造函数中传入 MyRunnable的实例对象。

Thread thread = new Thread(new MyRunnable());thread.start();

当线程运行时,它将会调用实现了Runnable接口的run方法。上例中将会打印出”MyRunnable running”。

(4)方式四:创建一个实现了Runnable接口的匿名类
Runnable myRunnable = new Runnable(){   public void run(){     System.out.println("Runnable running");   }}Thread thread = new Thread(myRunnable);thread.start();

注意:对于这两种方式哪种好并没有一个确定的答案,它们都能满足要求。就我个人意见,我更倾向于实现Runnable接口这种方法。因为线程池可以有效的管理实现了Runnable接口的线程,如果线程池满了,新的线程就会排队等候执行,直到线程池空闲出来为止。而如果线程是通过实现Thread子类实现的,这将会复杂一些。

4、线程同步与锁(synchronized)

Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。

(1)用法一:代码块

在多线程环境下,synchronized块中的方法获取了lock实例的monitor,如果实例相同,那么只有一个线程能执行该块内容。

Thread thread = new Thread(){   public void run(){     System.out.println("Thread Running");   synchronized(lock){..do something     }   }};thread.start();
(2)用法二:方法
 public synchronized int getX() {        return x++;    }

关于锁和同步,有一下几个要点:

  • 只能同步方法,而不能同步变量和类;
  • 每个对象只有一个锁;当提到同步时,应该清楚在什么上同步?也就是说,在哪个对象上同步。
  • 必同步类中所有的方法,类可以同时拥有同步和非同步方法;
  • 如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。也就是说:如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法;
  • 如果线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁的限制;
  • 线程睡眠时,它所持的任何锁都不会释放;
  • 线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁;
  • 同步损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块;

5、wait()与notify/notifyAll()

wait() 与 notify/notifyAll() 是放在同步代码块中的。当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。从这里可以看出,notify/notifyAll()执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。故,在实际编程中,我们应该尽量在线程调用notify/notifyAll()后,立即退出临界区。即不要在notify/notifyAll()后面再写一些耗时的代码。

6、join()

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

t.join();      //使调用线程 t 在此之前执行完毕。t.join(1000);  //等待 t 线程,等待时间是1000毫秒

调用t.join时,必须能够拿到线程t对象的锁,如果拿不到它是无法wait的,必须同步锁释放后才调用join方法,才能wait.

**相关链接
如何创建并运行java线程 http://www.importnew.com/20672.html
java线程:线程的同步于锁 http://lavasoft.blog.51cto.com/62575/99155/
JAVA多线程之wait/notify https://www.cnblogs.com/hapjin/p/5492645.html
java多线程中join方法的理解 http://uule.iteye.com/blog/1101994
java中的线程只要看这篇就够了 https://www.cnblogs.com/wxd0108/p/5479442.html

原创粉丝点击