Java 多线程入门

进程与线程多线程

在学习Java多线程以前,先简单复习一下进程与线程的知识。ide

进程:进程是系统进行资源分配和调度的基本单位,能够将进程理解为一个正在执行的程序,好比一款游戏。性能

线程:线程是程序执行的最小单位,一个进程可由一个或多个线程组成,在一款运行的游戏中一般会有界面学习

   更新线程、游戏逻辑线程等,线程切换的开销远小于进程切换的开销。this

 

 

                   图1spa

在图1中,蓝色框表示进程,黄色框表示线程。进程拥有代码、数据等资源,这些资源是共享的,3个线程均可线程

以访问,同时每一个线程又拥有私有的栈空间。3d

Java线程状态图 code

 

 线程的五种状态:对象

  1)新建状态(New):线程对象实例化后就进入了新建状态。

  2)就绪状态(Runnable):线程对象实例化后,其余线程调用了该对象的start()方法,虚拟机便会启

     动该线程,处于就绪状态的线程随时可能被调度执行。

  3)运行状态(Running):线程得到了时间片,开始执行。只能从就绪状态进入运行状态。

  4)阻塞状态(Blocked):线程由于某个缘由暂停执行,并让出CPU的使用权后便进入了阻塞状态。

    等待阻塞:调用运行线程的wait()方法,虚拟机会把该线程放入等待池。

    同步阻塞:运行线程获取对象的同步锁时,该锁已被其余线程得到,虚拟机会把该线程放入锁定池。

    其余线程:调用运行线程的sleep()方法或join()方法,或线程发出I/O请求时,进入阻塞状态。

  5)结束状态(Dead):线程正常执行完或异常退出时,进入告终束状态。

Java线程实现

Java语言提供了两种实现线程的方式:

1)经过继承Thread类实现线程

public class ThreadTest { public static void main(String[] args){ Thread thread = new MyThread(); //建立线程 thread.start();  //启动线程 } }
//继承Thread类
class MyThread extends Thread{ @Override public void run() { int count = 7; while(count>0){ System.out.println(count); try { Thread.sleep(1000);   } catch (InterruptedException e) { e.printStackTrace(); } count--; } } }

2)经过实现Runnable接口实现线程

public class ThreadTest { public static void main(String[] args){ Runnable runnable = new MyThread();
     //将Runnable对象传递给Thread构造器 Thread thread
= new Thread(runnable); thread.start(); } }
//实现了Runnable接口
class MyThread implements Runnable{ @Override public void run() { int count = 7; while(count>0){ System.out.println(count); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; } } }

两种方式都覆写了run()方法,run()方法内定义了线程的执行内容,咱们只能经过线程的start()方法

启动线程,且start()方法只能调用一次,当线程进入执行状态时,虚拟机会回调线程的run()方法。

接调用线程的run()方法,并不会启动线程,只会像普通方法一样去执行。

其实,Thread类自己也实现了Runnable接口。这两种方式均可以实现线程,但Java语言只支持单继

承,若是扩展了Thread类就没法再扩展其余类,远没有实现接口灵活。

线程经常使用方法

1)Thread类

  Thread():用于构造一个新的Thread。

  Thread(Runnable target):用于构造一个新的Thread,该线程使用了指定target的run方法。

  Thread(ThreadGroup group,Runnable target):用于在指定的线程组中构造一个新的Thread,该

  线程使用了指定target的run方法。

  currentThread():得到当前运行线程的对象引用。

  interrupt():将当前线程置为中断状态。

  sleep(long millis):使当前运行的线程进入睡眠状态,睡眠时间至少为指定毫秒数。

  join():等待这个线程结束,即在一个线程中调用other.join(),将等待other线程结束后才继续本线程。

  yield():当前执行的线程让出CPU的使用权,从运行状态进入就绪状态,让其余就绪线程执行。

2)Object类

  wait():让当前线程进入等待阻塞状态,直到其余线程调用了此对象的notify()或notifyAll()方法后,

  前线程才被唤醒进入就绪状态。

  notify():唤醒在此对象监控器上等待的单个线程。

  notifyAll():唤醒在此对象监控器上等待的因此线程。

       注:wait()、notify()、notifyAll()都依赖于同步锁,而同步锁是对象持有的,且每一个对象只有一个,因此

    这些方法定义在Object类中,而不是Thread类中。

3)yield()、sleep()、wait()比较

   wait():让线程从运行状态进入等待阻塞状态,而且会释放它所持有的同步锁。

   yield():让线程从运行状态进入就绪状态,不会释放它锁持有的同步锁。

   sleep():让线程从运行状态进入阻塞状态,不会释放它锁持有的同步锁。

线程同步

先看一个多线程模拟卖票的例子,总票数7张,两个线程同时卖票:

public class ThreadTest{ public static void main(String[] args){ Runnable r = new MyThread(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } class MyThread implements Runnable{ private int tickets = 7;   //票数
 @Override public void run(){ while(tickets>0){ System.out.println("tickets:"+tickets); tickets--; try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } } }

 运行结果:

运行结果不符合咱们的预期,由于两个线程使用共享变量tickets,存在着因为交叉操做而破坏数据的可能性,

这种潜在的干扰被称做临界区,经过同步对临界区的访问能够避免这种干扰。

在Java语言中,每一个对象都有与之关联的同步锁,而且能够经过使用synchronized方法或语句来获取或释放

这个锁。在多线程协做时,若是涉及到对共享对象的访问,在访问对象以前,线程必须获取到该对象的同步

锁,获取到同步锁后能够阻止其余线程得到这个锁,直到持有锁的线程释放掉锁为止。

public class ThreadTest{ public static void main(String[] args){ Runnable r = new MyThread(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } class MyThread implements Runnable{ private int tickets = 7; @Override public void run(){ while(tickets>0){ synchronized(this){ //获取当前对象的同步锁 if(tickets>0){ System.out.println("tickets:"+tickets); tickets--; try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } } } } }

运行结果:

synchronized用法:

1)synchronized方法:若是一个线程要在某个对象上调用synchronized方法,那么它必须先获取这个对象的

锁,而后执行方法体,最后释放这个对象上的锁,而与此同时,在同一个对象上调用synchronized方法的其余

线程将阻塞,直到这个对象的锁被释放为止。

public synchronized void show(){ System.out.println("hello world"); }

2)synchronized静态方法:静态方法也能够被声明为synchronized的,每一个类都有与之相关联的Class对象,

而静态同步方法获取的就是它所属类的Class对象上的锁,两个线程不能同时执行同一个类的静态同步方法,如

果静态数据是在线程之间共享的,那么对它的访问就必须利用静态同步方法来进行保护。

3)synchronized语句:静态语句可使咱们获取任何对象上的锁而不单单是当前对象上的锁,也可以让咱们定

义比方法还要小的同步代码区,这样可让线程持有锁的时间尽量短,从而提升性能。

private final Object lock = new Object(); public void show(){ synchronized(lock){ System.out.println("hello world"); } }
相关文章
相关标签/搜索