一、多线程相关关键字
Runnable、Thread:线程的父类,区别就是使用Runnable接口不可以使用Thread的相关的特性,如sleep等;
run:线程类中必须存在的方法;
start:启动一个线程,经常被面试的人提到,我很郁闷;
synchronized:同步锁,指定不同的对象,锁的内容不同,如一把锁可以锁门,也可以锁窗户;
wait:先休息休息,好了的时候再叫我,但别忘了先锁门哦;
notify:让一个等待的线程活动起来,效率高点;
notifyAll:让所有等待的线程都起来抢东西了,但我更安全;
sleep:先休息休息,一会儿自己醒来,除非你不让我休息了;
interrupt:休息这以久还没有等到,不等了,但是不是中断这个线程;
setDaemon:守护线程,请不要在乎我的存在,我是为主人服务的;
join:等等,好了再继续;
yield:不释放锁的等待,尽可能把优先级交给其它线程,不可以放到synchronized锁定中;
ThreadLocal:多线程我也不怕共享资源。
Volatile:参看 Java 理论与实践: 正确使用 Volatile 变量
二、实例
1、我是一个线程,展示一个简单的线程是怎么样练成的:
- public class IamThread extends Thread {
- public void run(){
- System.out.println("I am a thread" );
- }
- }
- 或者
- public class IamThread implements Runnable {
- public void run(){
- System.out.println("I am a thread" );
- }
- }
- 启动线程:
- new Thread( new IamThread()).start()
2、休息休息再说,这个是对sleep的简单使用,休息指定的时间后再工作,这里的时间设的长,是因为3要使用到它:
- public class IamThread extends Thread {
- public void run() {
- int i = 0 ;
- while ( true ) {
- try {
- sleep(1000000000 );
- } catch (InterruptedException e) {
- }
- System.out.println(i++);
- }
- }
- }
3、睡醒了吧,懒虫,不要一直让他沉睡,过2秒钟醒他一下,“工作”后,再继续睡,然后再过2秒钟再弄醒一下...如些循环,这里需要注意一下方法interrupt(),不要把这个理解为中断线程,理解为把当程线程唤醒更贴切:
- public class RunThread {
- public static void main(String[] args) {
- Thread thread = new Thread( new IamThread());
- thread.start();
- while ( true ) {
- try {
- Thread.sleep(2000 );
- } catch (InterruptedException e) {
- }
- thread.interrupt();
- }
- }
- }
4、饭好了叫我,对wait的使用示例,将线程放入到虚拟的wait set中,当对线程使用wait时,但是要想使用wait等待线程,需要注意两点,一是必须要获取锁定,如这里的synchroinzed关键字,二是必 须要有notify()或notifyAll()方法来叫醒,否则线程会永远醒不过来:
- public class WaitThread extends Thread {
- private boolean isReady = false ;
- public synchronized void eat(){
- if (!isReady){
- try {
- wait();
- } catch (InterruptedException e) {}
- }
- System.out.println("I eat happy!" );
- }
- public synchronized void cook(){
- isReady = true ;
- //notify();
- notifyAll();
- }
- }
5、Join,全部好了再走,JOIN的使用情况是要获取到一个线程或者多个线程执行结果后,再继续执行下面的步骤,如果用采用JOIN,也许启动的线程 还没有执行完毕,JVM就退出了;既然JVM可以等到线程执行完后再继续下面的步骤,我们可否使用JOIN来做分布式运算,这个你自己想哦:
- public class JoinThread extends Thread {
- private static int n = 0 ;
- public void run() {
- for ( int i = 0 ; i < 10 ; i++)
- try {
- addN();
- //sleep(3); // 为了使运行结果更随机,延迟3毫秒
- } catch (Exception e) {}
- }
- private synchronized void addN() {n++;}
- public static void main(String[] args) throws Exception {
- Thread threads[] = new Thread[ 100 ];
- for ( int i = 0 ; i < threads.length; i++) {
- threads[i] = new JoinThread();
- }
- for ( int i = 0 ; i < threads.length; i++) {
- threads[i].start();
- }
- // if (args.length > 0) {
- for ( int i = 0 ; i < threads.length; i++) {
- // 100个线程都执行完后继续
- threads[i].join();
- }
- // }
- System.out.println("n=" + JoinThread.n);
- }
- }
注:以上的示例,并不是每次都会得到1000,这个我目前没有想明白是为什么,因为当上面执行到最后的输出的时候,启动的100个线程都已经执行完了,如果你有答案,请告诉我,我会非常感谢。
6、守护线程,JVM不需要依赖于守护线程是否执行完毕来确定是否退出,他的优先级很低,如垃圾收集集,待其它的线程需要执行时,袒护线程就会等其它线程 执行,如果全部执行完了,虚拟机不会在意守护线程是否还有任务在执行,都会退出。简单的理解为守护线程为家仆,其它线程为主人,只需要看主人的脸色,而不 会在科家仆的脸色,主人完了,那家仆完不完已经不重要了:
- public class RunDeamonThread {
- public static void main(String[] args){
- Thread doorKeeper = new Thread( new DoorKeeper());
- doorKeeper.setDaemon(true );
- doorKeeper.start();int i= 0 ;
- while (i< 100 ){
- Thread thread = new Thread( new IamThread());
- thread.start();
- i++;
- }
- }
- }
- class DoorKeeper extends Thread{
- public void run(){
- while ( true ){
- System.out.println("I am a door guander,don't care me!" );
- }
- }
- }
7、ThreadLocal,用于在线程中传递变量
只有四个方法:
get() 返回此线程局部变量的当前线程副本中的值。
initialValue() 返回此线程局部变量的当前线程的“初始值”。只在get或set时执行一次
remove() 移除此线程局部变量当前线程的值。
set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值。
- public class ThreadGlobalTest {
- private static ThreadLocal<String> priviewStatus =
- new ThreadLocal<String>();
- public static String getPriviewStatus() {
- return priviewStatus.get();
- }
- public static void setPriviewStatus(String status) {
- priviewStatus.set(status);
- }
- }
8、yield,我一直等待,但是我也一直在工作,条件好了我就闪
- public class YieldTest {
- private volatile boolean ready;
- //注意此方法不可以加synchronized,因为yield是一种不会释放锁的等待
- public void doSomething() {
- while (!ready) {
- Thread.yield();
- }
- }
- public synchronized void setReady() {
- ready = true ;
- }
- }
三、一个巩固实例
这个实例是别人发到JAVAEYE上面的,我看的蛮有意思的,就贴在这里,
- public class Test {
- public static void main(String[] args) {
- MyClass1 myClass = new MyClass1();
- new MyThread(myClass).start();
- new MyThread1(myClass).start();
- }
- }
- class MyClass1 {
- public synchronized void m1() {
- System.out.println("m1-1" );
- try {
- this .wait(); // 暂停改当前线程,并且会释放锁
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("m1-2" );
- try {
- Thread.sleep(1000 ); // m1和m2同时暂停1秒钟
- System.out.println("m1-3" );
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("m1-4" );
- m2();
- }
- public synchronized void m2() {
- System.out.println("m2-1" );
- this .notifyAll(); // 叫醒m1
- System.out.println("m2-2" );
- try {
- Thread.sleep(1000 );
- System.out.println("m2-3" );
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("m2-4" );
- m1();
- }
- }
- class MyThread extends Thread {
- private MyClass1 myClass;
- public MyThread(MyClass1 myClass){
- this .myClass = myClass;
- }
- @Override
- public void run() {
- myClass.m1();
- }
- }
- class MyThread1 extends Thread {
- private MyClass1 myClass;
- public MyThread1(MyClass1 myClass){
- this .myClass = myClass;
- }
- @Override
- public void run() {
- try { // 暂停10毫秒是为了让m1先执行wait
- Thread.sleep(10 );
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- }
- myClass.m2();
- }
- }