首页 > 代码库 > java 多线程

java 多线程

10

线程的状态

技术分享

 

首先新建一个线程,然后启动,启动后变成runnable状态,表示已经准备就绪可以执行了,或者正在执行当中。执行完了后终止。

blocked:访问临界区,如果拿不到临界区的资源,需要等待。被动的等待。

waiting:主动发起的等待。自己的数据没准备好。

timedwaiting:限时等待。跟waiting相似。这个有时间限制,比如设置5秒钟。不管5秒内数据有没有准备好,都执行。waiting是不限时间的等待。

线程的基本操作

        Thread t1 = new Thread(){   //新建线程
            @Override
            public void run(){
                System.out.println("hello");
            }
        };
        t1.start();  //启动线程,run方法被执行
Thread t1 = new Thread();
t1.run();//在当前线程中执行。不是另外开启的线程。要想异步,必须start

不用重载run方法。使用Runable接口实现。

public class testRunable implements Runnable{
    public static void main(String[] args) {
        Thread t1 = new Thread(new testRunable()); //传入参数的模式。一般推荐
        t1.start();
    }
    @Override
    public void run() {
        System.out.println("OK");
    }
}

终止线程

Thread.stop();//不推荐使用。他会释放所有的monitor。有可能一个类中其他赋值还没有完成就停止了。这样就造成数据不同步,把对象写坏。会释放锁

中断线程,写一个支持中断的线程,可以有效的控制数据不被写坏。

t1.interrupt();//中断线程
Thread.currentThread().isInterrupted(); ///判断是否被中断
Thread.currentThread().interrupted();//判断是否被中断,并清除当前中断状态。

sleep 线程睡眠。释放cpu。抛出异常后,会清除中断标记位,所以需要在抛出异常的时候,再次中断。

    public void run() {
        // TODO Auto-generated method stub
        while(true){
            if(Thread.currentThread().isInterrupted()){ //线程被中断 退出
                break;
            }
            try {
                Thread.sleep(20000); //如果睡眠被中断,就会醒来
            }
            catch(InterruptedException e){  //抛出异常后,会清除中断标记位
                System.out.println("interrupted when sleep"); 
                Thread.currentThread().interrupt(); //设置中断  这样 当再次回到while循环的时候,就能判别有没有被中断。
                
            }
            Thread.yield();
        }
    }
}

挂起 suspend和 继续执行resume。这两个方法都是被废弃的。

suspend不会释放锁

如果枷锁发生resume之前,会发生死锁。

等待线程结束 join和谦让yeild

public class JoinMain {
    public volatile static int i = 0;
    public static class AddThread extends Thread {
        @Override
        public void run() {
            for (i = 0; i < 1000000; i++);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        AddThread at = new AddThread();
        at.start();
        at.join(); //主线程停止执行,等待线程执行完,再打印i的值
        System.out.println(i);
    }
}

join的本质

while (isAlive()){ //判断当前线程还活着,当线程执行完毕后,系统会调用 notifyAll()
   wait(0); //调用wait方法
}
//不要在Thread实例上使用wait() 和notify()方法 这样会干扰jdk内部实现。

synchronized 用来管理和控制临界区。

-给指定对象加锁:给指定对象加锁。进入同步代码前要获得给定对象的锁

-给实例方法加锁:相当于对实例加锁。进入同步代码前要获得当前实例的锁

-给静态放假加锁:相当于给当前类加锁。进入同步代码前要获得当前类的锁

public class SynchronizedTest extends Thread {
    public Object instance;
    public static int i;
    @Override
    public void run(){
        for(int j=0;j<100000;j++){
            //指定枷锁对象 一次只有一个线程
            synchronized(instance){
                i++;
            }
        }
    }
    //用在方法上  表示increase所在的对象上加锁  如果每次生成不同的实例,这个锁是没有用的
    public synchronized void increase(){
        i++;
    }
    // 表示给increase2 所在的类上加锁 。就算有不同的锁也可以锁住,因为类只有一个
    public static synchronized void increase2(){
        i++;
    }
}
public class Accounting implements Runnable {
    static Accounting instance = new Accounting();
    static int i=0;
    //锁加载Accounting类上  是可以锁住的
    public synchronized static void increase(){
        i++;
    }
//    锁加在instance实例上  也是可以锁住的  输出2000000
//    public synchronized  void increase(){
//        i++;
//    }
    @Override
    public void run() {
        for (int j=0;j<1000000;j++){
            increase();
        }
    }
    public static void main(String[] args) throws InterruptedException{
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();t2.start();
        t1.join(); t2.join();
        System.out.println(i);  //运行结果,输出2000000      
    }
}
public class Accounting implements Runnable {
    static Accounting instance = new Accounting();
    static int i=0;
    //锁加在instance实例上 
    public  synchronized  void increase(){
        i++;
    }
    @Override
    public void run() {
        for (int j=0;j<1000000;j++){
            increase();
        }
    }
    public static void main(String[] args) throws InterruptedException{
        Thread t1 = new Thread(new Accounting());
 Thread t2 = new Thread(new Accounting());
        t1.start();t2.start();
        t1.join(); t2.join();
        System.out.println(i);  //因为初始化了不同的实例 所以是锁不住的  需要把increase 改成static
    }
}

Object.wait() 让线程等待。一般是数据没有准备好,所以等待

Object.notify() 通知在这个对象上等待的线程,可以继续工作了。不用再等待了。 如果有多个等待的线程,会随机先通知一个。

public class wnTest {
    public Object object = new Object();
    public class wn2 extends Thread {
        public void run(){
            synchronized(object){
                System.out.println(System.currentTimeMillis()+" :wn2 start!notify one thread");
                object.notify();
                System.out.println(System.currentTimeMillis()+" :wn2 end!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public class wn1 extends Thread {
        public void run(){
            synchronized(object){
                System.out.println(System.currentTimeMillis()+" :wn1 start!");
                try {
                    System.out.println(System.currentTimeMillis()+" :wn1 wait for object");
                    object.wait();
                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis()+" :wn1 end!");
            }
        }
    }
    public void ext(){
        wn1 w = new wn1();
        wn2 w2 = new wn2();
        w.start();
        w2.start();
    }
    public static void main(String[] args) {
        new wnTest().ext();
    }
}
//执行结果
1498404259216 :wn1 start!
1498404259216 :wn1 wait for object
1498404259216 :wn2 start!notify one thread
1498404259216 :wn2 end!  
1498404261221 :wn1 end! //因为有个sleep操作,wn2不能马上执行完,导致wn1不能马上拿到锁。所以有时间差

线程安全

当多个线程对同一arraylist进行添加时,可能一个线程获取到的arraylist size为5 而另一个线程获取arrayList的size为3,当给arralist继续添加的时候,就会增加到第四个。但第四个已经被线程一添加过了。所以会抛出异常,而且获取的总是是小于预期的。

public class ArrayListMultiThread {
    static ArrayList<Integer> al = new ArrayList<Integer>(10);
    public static class AddThread implements Runnable{
        @Override
        public void run() {
            for (int i=0;i<1000;i++){
                al.add(i);
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new AddThread());
        Thread t2 = new Thread(new AddThread());
        t1.start();t2.start();
        t1.join(); t2.join();
        System.out.println(al.size()); //抛出异常 返回小于2000的数值。
    }
}

包装为线程安全的

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
public class safeArrayList {
    //将list变为线程安全的方法 对于所有的集合都是通用的
    static List<Integer> al = Collections.synchronizedList(new LinkedList<Integer>());
    public static List<String> l =   Collections.synchronizedList(new LinkedList<String>());
    public static List<String> l2 =   new Vector();
    public static List<String> l3=new CopyOnWriteArrayList<String>();
    public static class AddThread implements Runnable{
        @Override
        public void run() {
            for (int i=0;i<1000;i++){
                al.add(i);
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new AddThread());
        Thread t2 = new Thread(new AddThread());
        t1.start();t2.start();
        t1.join(); t2.join();
        System.out.println(al.size()); //2000
    }
}
    public static Map m= Collections.synchronizedMap(new HashMap()); 
    public static Map m2 = new ConcurrentHashMap();
ConcurrentHashMap的性能高于Collections.synchronizedMap。因为ConcurrentHashMap不是锁整个hashmap。而是把hashmap继续分成16个segments,每一个segments都是一个hashmap,每一次对它操作的时候,不需要锁整个对象,当有一个对象进来后,先锁整个对象,再查落在哪一个segments,然后锁单个segments就行。提高哦并发度。所以推荐。

 

java 多线程