Solo  当前访客:0 开始使用

多线程的使用(基础)


一、新启线程的方式
1、

public class NewThread {
	
	/*扩展自Thread类*/
	private static class UseThread extends Thread{
		@Override
		public void run() {
			super.run();
			//do my work
			System.out.println("I am extended Thread.");
		}
	}
	
	/*实现Runnable接口*/
	private static class UseRunnable implements Runnable{
		@Override
		public void run() {
			//do my work
			System.out.println("I am implements Runnable.");
		}
	}
	
	/*实现Callable接口,允许有返回值*/
	private static class UseCallable implements Callable<String>{
		@Override
		public String call() throws Exception {
			//do my work
			System.out.println("I am implements Callable.");
			return "CallResult";
		}
	}
	
	public static void main(String[] args) 
			throws InterruptedException, ExecutionException {
		UseThread useThread = new UseThread();
		useThread.start();
		
		UseRunnable useRunnable = new UseRunnable();
		new Thread(useRunnable).start();
		
		UseCallable useCallable = new UseCallable();
		FutureTask<String> futureTask //用FutureTask包装Callable
			= new FutureTask<>(useCallable);
		new Thread(futureTask).start();//交给Thread去运行
		System.out.println("Get UseCallable result = "+futureTask.get());
		
	}

}

future使用:

public class UseFuture {

	
	
	/*实现Callable接口,允许有返回值*/
	private static class UseCallable implements Callable<Integer>{
		private int sum;
		@Override
		public Integer call() throws Exception {
			System.out.println("Callable子线程开始计算!");  
			Thread.sleep(2000);
	        for(int i=0 ;i<5000;i++){  
	            sum=sum+i;  
	        }  
	        System.out.println("Callable子线程计算结束!结果为: "+sum);  
	        return sum; 
		}
	}
	
	public static void main(String[] args) 
			throws InterruptedException, ExecutionException {
		
		UseCallable useCallable = new UseCallable();
		FutureTask<Integer> futureTask //用FutureTask包装Callable
			= new FutureTask<>(useCallable);
		new Thread(futureTask).start();//交给Thread去运行
		Random r = new Random();
		Thread.sleep(1000);
		if(r.nextBoolean()) {//用随机的方式决定是获得结果还是终止任务
			System.out.println("Get UseCallable result = "+futureTask.get());
		}else {
			System.out.println("中断计算。  ");
			futureTask.cancel(true);
		}
		
	}

}

2、守护线程:Thread.setDaemon(true);

二、线程中断
1、

	private static class UseRunnable implements Runnable{
		
		@Override
		public void run() {
			while(!Thread.currentThread().isInterrupted()) {//改为true,线程不会中断;改为Thread.interrupted(),标志位被复位
				System.out.println(Thread.currentThread().getName()
						+ " I am implements Runnable.");
			}
			System.out.println(Thread.currentThread().getName()
					+" interrupt flag is "+Thread.currentThread().isInterrupted());
		}
	}

	public static void main(String[] args) throws InterruptedException {
		UseRunnable useRunnable = new UseRunnable();
		Thread endThread = new Thread(useRunnable,"endThread");
		endThread.start();
		Thread.sleep(20);
		//中断
		endThread.interrupt();
	}

2、
interrupted()是静态方法:内部实现是调用的当前线程的isInterrupted(),并且会重置当前线程的中断状态

isInterrupted()是实例方法,是调用该方法的对象所表示的那个线程的isInterrupted(),不会重置当前线程的中断状态

阻塞方法中抛出InterruptedException异常后,如果需要继续中断,需要手动再中断一次

三、
Java 内存模型中的可见性、原子性和有序性:
1、可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。**也就是一个线程修改的结果。另一个线程马上就能看到。

2、原子是世界上的最小单位,具有不可分割性。**比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。在 Java 中 synchronized 和在 lock、unlock 中操作保证原子性。

3、Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。

Volatile只保证内存可见性,不保证操作的原子性
4、volatile的使用

public class UseVola {

	

	private volatile int age = 100000;

	
    private static class TestThread extends Thread{
    	
    	private UseVola synTest;
    	
    	public TestThread(UseVola synTest,String name) {
    		super(name);
    		this.synTest = synTest;
		}
    	
    	@Override
	    public void run() {
    		for(int i=0;i<100000;i++) {
    			synTest.test();
    		}
			System.out.println(Thread.currentThread().getName()
					+" age =  "+synTest.getAge());
	    }
    }
    
	public void test() {
		age++;
	}
	
	public int getAge() {
		return age;
	}
	

	public static void main(String[] args) throws InterruptedException {
		UseVola synTest = new UseVola();
		Thread endThread = new TestThread(synTest,"endThread");
		endThread.start();
		SleepTools.ms(5);
		System.out.println(Thread.currentThread().getName()
				+" age =  "+synTest.getAge());		

	}
}

5、演示violate无法提供操作的原子性

public class VolatileUnsafe {
	
	private static class VolatileVar implements Runnable {
		
	    private volatile int a = 0;

	    @Override
	    public void run() {
            a = a + 1;
            System.out.println(Thread.currentThread().getName() + ":----" + a);
            SleepTools.ms(100);
            a = a + 1;
            System.out.println(Thread.currentThread().getName() + ":----" + a);
	    }
	}
	
    public static void main(String[] args) {

    	VolatileVar v = new VolatileVar();

        Thread t1 = new Thread(v);
        Thread t2 = new Thread(v);
        Thread t3 = new Thread(v);
        Thread t4 = new Thread(v);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}

6、synchronized关键字的作用

public class SynTest {

	
	private int age = 100000;//初始100000
	
    private static class TestThread extends Thread{
    	
    	private SynTest synTest;
    	
    	public TestThread(SynTest synTest,String name) {
    		super(name);
    		this.synTest = synTest;
		}
    	
    	@Override
	    public void run() {
    		for(int i=0;i<100000;i++) {//递增100000
    			synTest.test();
    		}
			System.out.println(Thread.currentThread().getName()
					+" age =  "+synTest.getAge());
	    }
    }
    
	public synchronized void test() {
		age++;
	}
	
	public void test2() {
		synchronized(this){
			age--;
		}
	}
	
	public int getAge() {
		return age;
	}
	

	public static void main(String[] args) throws InterruptedException {
		SynTest synTest = new SynTest();
		Thread endThread = new TestThread(synTest,"endThread");
		endThread.start();
		for(int i=0;i<100000;i++) {//递减100000
			synTest.test2();
		}
		System.out.println(Thread.currentThread().getName()
				+" age =  "+synTest.getAge());		

	}
}

7、 调用yield() 、sleep()、join()、wait()、notify()
yield() 使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了,不释放锁

join()的主要作用就是同步**,它可以使得线程之间的并行执行变为串行执行

sleep()使调用该方法的线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行,不释放锁

wait()使当前线程阻塞,前提是必须先获得锁,一般配合synchronized 关键字使用,调用前持有所,后会释放锁
Notify  唤醒某一个wait()线程,(随机唤醒),会释放锁

notifyAll 唤醒所有

演示demo:
join():

public class UseJoin {
    static class JumpQueue implements Runnable {
        private Thread thread;

        public JumpQueue(Thread thread) {
            this.thread = thread;
        }

        public void run() {
            try {
                thread.join();//调用传入线程的join方法,必须等这个方法返回后,当前线程才能继续执行
            } catch (InterruptedException e) {
            }
            System.out.println(Thread.currentThread().getName() + " terminate.");
        }
    }

    public static void main(String[] args) throws Exception {
        Thread previous = Thread.currentThread();//现在previous是主线程
        for (int i = 0; i < 10; i++) {
            // 每个线程拥有前一个线程的引用,需要等待前一个线程终止,才能从等待中返回
            Thread thread =
                    new Thread(new JumpQueue(previous), String.valueOf(i));
            System.out.println(previous.getName()+" jump a queue the thread:"
                    +thread.getName());
            thread.start();
            //传入当前线程
            previous = thread;
        }

        SleepTools.second(2);//让主线程休眠2秒
        System.out.println(Thread.currentThread().getName() + " terminate.");
    }
}

wait/notify/notifyAll

public class Express {

    public final static String CITY = "ShangHai";

    private int km;/*快递运输里程数*/

    private String site;/*快递到达地点*/

    public Express() {
    }

    public Express(int km, String site) {
        this.km = km;
        this.site = site;
    }

    /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
    public synchronized void changeKm(){
        this.km = 101;
        notifyAll();
    }

    /* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
    public  synchronized  void changeSite(){
        this.site = "BeiJing";
        notifyAll();
    }

    public synchronized void waitKm(){
        while(this.km<=100){//公里数小于100不做处理
            try {
                wait();
                System.out.println("Check Km thread["+Thread.currentThread().getId()
                		+"] is be notified");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("the Km is "+this.km+",I will change db");
    }

    public synchronized void waitSite(){
        while(this.site.equals(CITY)){//快递到达目的地
            try {
                wait();
                System.out.println("Check Site thread["+Thread.currentThread().getId()
                		+"] is be notified");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("the site is "+this.site+",I will call user");
    }
}

public class TestWN {
    private static Express express = new Express(0,Express.CITY);

    /*检查里程数变化的线程,不满足条件,线程一直等待*/
    private static class CheckKm extends Thread{
        @Override
        public void run() {
        	express.waitKm();
        }
    }

    /*检查地点变化的线程,不满足条件,线程一直等待*/
    private static class CheckSite extends Thread{
        @Override
        public void run() {
        	express.waitSite();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for(int i=0;i<3;i++){
            new CheckSite().start();
        }
        for(int i=0;i<3;i++){
            new CheckKm().start();
        }

        Thread.sleep(1000);
        //express.changeKm();//快递地点变化
        express.changeSite();
    }
}

8、ThreadLocal的使用
使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

public class UseThreadLocal {
	/*声明一个ThreadLocal类型的static变量,所有线程共享,并初始化为1*/
    static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 1;
        }
    };

    /**
     * 运行3个线程
     */
    public void StartThreadArray(){
        Thread[] runs = new Thread[3];
        for(int i=0;i<runs.length;i++){
            runs[i]=new Thread(new TestThread(i));
        }
        for(int i=0;i<runs.length;i++){
            runs[i].start();
        }
    }
    
    /**
     *类说明:测试线程,线程的工作是将ThreadLocal变量的值变化,并写回,看看线程之间是否会互相影响
     */
    public static class TestThread implements Runnable{
        int id;
        public TestThread(int id){
            this.id = id;
        }
        public void run() {
            System.out.println(Thread.currentThread().getName()+":start");
            Integer s = threadLocal.get();//获得变量的值
            s = s+id;
            threadLocal.set(s);//将值写回变量
            System.out.println(Thread.currentThread().getName()+':'+threadLocal.get());
        }
    }

    public static void main(String[] args){
    	UseThreadLocal test = new UseThreadLocal();
        test.StartThreadArray();
    }
}
0 0