java并发编程之初识线程

java并发编程之初识线程

  • 说明
    • 线程生命周期
    • 线程创建
    • 线程间通信
    • 线程池
    • 生产者消费者实例
    • 多线程买票案例
    • 多线程切换等待唤醒交替打印奇偶数

说明

操作系统运行一个程序就会创建一个进程,例如我们一个main函数程序启动了,就会创建一个java进程,然后有一个main主线程和其他线程(至少一个垃圾回收线程),这时我们如果想java做的任务更多时间更少就可以创建更多线程,这样能够最大化利用cpu,更快响应。

线程生命周期

java并发编程之初识线程_第1张图片

线程创建

  • 继承Thread类创建线程
代码实例

public class MyThread extends Thread{//继承Thread类

  public void run(){

  //重写run方法

  }

}

public class Main {

  public static void main(String[] args){

    new MyThread().start();//创建并启动线程

  }

}

  • 实现Runnable接口创建线程
public class MyThread2 implements Runnable {//实现Runnable接口

  public void run(){

  //重写run方法

  }

}

public class Main {

  public static void main(String[] args){

    //创建并启动线程

    MyThread2 myThread=new MyThread2();

    Thread thread=new Thread(myThread);

    thread().start();

    //或者    new Thread(new MyThread2()).start();

  }

}

  • 使用Callable和Future创建线程
       FutureTask futureTask = new FutureTask(()->7);

        new Thread(futureTask).start();
        try {
            futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
  • 使用线程池例如用Executor框架
   Executor框架包括:线程池,Executor,Executors,ExecutorService,
   CompletionService,Future,Callable等。
Executor执行Runnable任务
public class TestCachedThreadPool{   
    public static void main(String[] args){   
        ExecutorService executorService = Executors.newCachedThreadPool();   
//      ExecutorService executorService = Executors.newFixedThreadPool(5);  
//      ExecutorService executorService = Executors.newSingleThreadExecutor();  
 //       ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);

        for (int i = 0; i < 5; i++){   
            executorService.execute(new TestRunnable());   
            System.out.println("************* a" + i + " *************");   
        }   
        executorService.shutdown();   
    }   
}   
  
class TestRunnable implements Runnable{   
    public void run(){   
        System.out.println(Thread.currentThread().getName() + "线程被调用了。");   
    }   
} 
Executor执行Callable任务
public class CallableDemo{   
    public static void main(String[] args){   
        ExecutorService executorService = Executors.newCachedThreadPool();   
        List> resultList = new ArrayList>();   
  
        //创建10个任务并执行   
        for (int i = 0; i < 10; i++){   
            //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中   
            Future future = executorService.submit(new TaskWithResult(i));   
            //将任务执行结果存储到List中   
            resultList.add(future);   
        }   
  
        //遍历任务的结果   
        for (Future fs : resultList){   
                try{   
                    while(!fs.isDone);//Future返回如果没有完成,则一直循环等待,直到Future返回完成  
                    System.out.println(fs.get());     //打印各个线程(任务)执行的结果   
                }catch(InterruptedException e){   
                    e.printStackTrace();   
                }catch(ExecutionException e){   
                    e.printStackTrace();   
                }finally{   
                    //启动一次顺序关闭,执行以前提交的任务,但不接受新任务  
                    executorService.shutdown();   
                }   
        }   
    }   
}   
  
  
class TaskWithResult implements Callable{   
    private int id;   
  
    public TaskWithResult(int id){   
        this.id = id;   
    }   
  
    /**  
     * 任务的具体过程,一旦任务传给ExecutorService的submit方法, 
     * 则该方法自动在一个线程上执行 
     */   
    public String call() throws Exception {  
        System.out.println("call()方法被自动调用!!!    " + Thread.currentThread().getName());   
        //该返回结果将被Future的get方法得到  
        return "call()方法被自动调用,任务返回的结果是:" + id + "    " + Thread.currentThread().getName();   
    }   
}
/** * <三> 使用ExecutorCompletionService管理异步任务 * 
 * 1. Java中的ExecutorCompletionService本身有管理任务队列的功能 
 * i. ExecutorCompletionService内部维护列一个队列, 用于管理已完成的任务 
 * ii. 内部还维护列一个Executor, 可以执行任务 
 * 2. ExecutorCompletionService内部维护了一个BlockingQueue, 只有完成的任务才被加入到队列中 
 * 3. 任务一完成就加入到内置管理队列中, 如果队列中的数据为空时, 调用take()就会阻塞 (等待任务完成) * i. 关于完成任务是如何加入到完成队列中的, 请参考ExecutorCompletionService的内部类QueueingFuture的done()方法 
 * 4. ExecutorCompletionService的take/poll方法是对BlockingQueue对应的方法的封装, 关于BlockingQueue的take/poll方法: 
 * i. take()方法, 如果队列中有数据, 就返回数据, 否则就一直阻塞; 
 * ii. poll()方法: 如果有值就返回, 否则返回null * iii. poll(long timeout, TimeUnit unit)方法: 如果有值就返回, 否则等待指定的时间; 如果时间到了如果有值, 就返回值, 否则返回null
 * 解决了已完成任务得不到及时处理的问题 */
 ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(Executors.newSingleThreadExecutor());
        executorCompletionService.submit(()->7);
        try {
            Future take = executorCompletionService.take();
            Integer integer = take.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

线程间通信

  Java中线程通信协作的最常见的两种方式:

  一.syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()

  二.ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()

  线程间直接的数据交换:

  三.通过管道进行线程间通信:1)字节流;2)字符流   

线程池

        ExecutorService executorService = Executors.newCachedThreadPool();   
//      ExecutorService executorService = Executors.newFixedThreadPool(5);  
//      ExecutorService executorService = Executors.newSingleThreadExecutor();  
 //       ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
         BlockingQueue blockingQueue= new ArrayBlockingQueue(10);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 5, 60,    TimeUnit.SECONDS,blockingQueue);
        threadPoolExecutor.execute();

生产者消费者实例

package com.jp.oneone;

public class ValueObject {

    public static String value = "";

}
package com.jp.oneone;

//生产者
public class P extends Thread{

    private String lock;

    public P(String lock) {
        super();
        this.lock = lock;
    }
    
    @Override
    public void run() {
        while (true) {
            try {
                synchronized (lock) { //当前线程必须获得锁才可以进行下面的操作
                    if (!ValueObject.value.equals("")) {//如果Value不为空,说明字符串还没被消费,所以调用wait方法,把当前线程(生成线程)阻塞
                        lock.wait();
                    }
                    String value = System.currentTimeMillis() + "_"
                            + System.nanoTime();
                    System.out.println("set的值是" + value);
                    ValueObject.value = value;//为空的话,则生成
                    lock.notify();//生成完就唤醒等待该对象锁的线程,(这里只有一个消费者等这个锁,所以就是唤醒的它)
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

package com.jp.oneone;

//消费者
public class C extends Thread {

    private String lock;

    public C(String lock) {
        super();
        this.lock = lock;
    }
    
    @Override
    public void run() {
        while (true) {
            try {
                synchronized (lock) {
                    if (ValueObject.value.equals("")) {//如果字符串为空,即被消费完了,所以wait等待。
                        lock.wait();
                    }
                    System.out.println("get的值是" + ValueObject.value);
                    ValueObject.value = "";
                    lock.notify();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.jp.oneone;

public class Run {

    public static void main(String[] args) {

        String lock = new String("");
        P p = new P(lock);
        C r = new C(lock);

        p.start();
        r.start();
    }

}



再来一版
package oneone;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private ReentrantLock lock = new ReentrantLock();//拿到可重入锁,相当于synchronized的作用
    private Condition condition = lock.newCondition();//调用await和signal方法的对象,相当于Object对象(任意对象)的的wait和notify方法
    private boolean hasValue = false;

    //生产者
    public void set() {
        try {
            lock.lock();//获得锁
            while (hasValue == true) {
                condition.await(); //没被消费则阻塞该生产线程,当然也释放了锁,进入等锁的队列
            }
            System.out.println("打印★");
            hasValue = true;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
    //消费者
    public void get() {
        try {
            lock.lock();
            while (hasValue == false) {
                condition.await();
            }
            System.out.println("打印☆");
            hasValue = false;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

package oneone;

public class MyThreadA extends Thread {

    private MyService myService;

    public MyThreadA(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            myService.set();
        }
    }

}


package oneone;


public class MyThreadB extends Thread {

    private MyService myService;

    public MyThreadB(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            myService.get();
        }
    }

}
package oneone;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();

        MyThreadA a = new MyThreadA(myService);
        a.start();

        MyThreadB b = new MyThreadB(myService);
        b.start();

    }
}

多线程买票案例

class Xc implements Runnable{
	public static int chepiao = 100;
	//synchronized的作用是,让它所管辖的代码部分,要么全部执行完,要么全部不执行,synchronized既可修饰代码块,又可以修饰函数
//	如果是锁整个方法,可以在方法内加锁,表达上比如public synchronized void run(){,但对于此案例,是两个线程之间竞争售票,因此不适宜锁起来整个方法
	//如果synchronized是锁起来整个方法的,synchronized修饰函数不需要传入字符串参数,相当于默认是this
	public void run(){
		while (true) {
			synchronized (" ") {//在需要加锁保证完整运行的代码块旁边加上synchronized (" "){}包裹代码,即可锁起来该部分代码,()内的字符串随意定义
				if(chepiao>0){
					System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");
					--chepiao;
				}else{
					break;
				}
			}
		}
	}
}
public class XianCheng {
	public static void main(String [] args){
		Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc1.start();
		Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc2.start();
	}
}

多线程切换等待唤醒交替打印奇偶数

package com.svse.thread;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * 交替打印奇偶数
 *功能说明:
 *@author:zsq
 *create date:2019年5月27日 下午4:34:30
 *修改人   修改时间  修改描述
 *
 *Copyright (c)2019北京智华天成科技有限公司-版权所有
 */
public class AlternatePrinting {
	  //让两个线程使用同一把锁。交替执行 。
	  //判断是不是奇数 如果是奇数进入奇数线程执行打印并加一。然后线程释放锁资源。然后让该线程等待
	  //判断是不是偶数,如果是偶数进入偶数线程执行打印并加一。然后线程释放锁资源。然后让该线程等待
	  public static AtomicInteger atomicInteger =new AtomicInteger(1);
	
	  public static void main(String[] args) {
		    Thread a=new Thread(new AThread());
		    Thread b=new Thread(new BThread());
		    a.start();
		    b.start();
	  }
	
	
	  //奇数线程
	  public static class AThread implements Runnable{
	            public void run() {
	                 while(true){
	        	           synchronized (atomicInteger) {
					        if(atomicInteger.intValue()%2 !=0){
						          System.out.println("奇数线程:" + atomicInteger.intValue());
						          try {
							            Thread.sleep(500);
						          } catch (InterruptedException e1) {
							            // TODO Auto-generated catch block
							            e1.printStackTrace();
						          }
						          atomicInteger.getAndIncrement(); // 以原子方式将当前值加 1。
						          // 奇数线程释放锁资源
						          atomicInteger.notify();//执行完操作后释放锁并进入等待
						          try {
							            atomicInteger.wait();
						          } catch (InterruptedException e) {
							            e.printStackTrace();
						          }
					        }else{
						          // 奇数线程等待
						          try {
							            atomicInteger.wait();
						          } catch (InterruptedException e) {
							            // TODO Auto-generated catch block
							            e.printStackTrace();
						          }
					        }
				      }
	                }
	            }
	  }
 
	   //偶数线程
	  public static class BThread implements Runnable{
		    public void run() {
			      while(true){
				       synchronized (atomicInteger) {
					       if(atomicInteger.intValue()%2 ==0){
						           System.out.println("偶数线程:"+ atomicInteger.intValue());
						           try {
								            Thread.sleep(500);
							          } catch (InterruptedException e1) {
								            // TODO Auto-generated catch block
								            e1.printStackTrace();
							          }
						         atomicInteger.getAndIncrement(); // 以原子方式将当前值加 1。
						         // 偶数线程释放锁资源
						         atomicInteger.notify();//执行完操作后释放锁并进入等待
						         try {
							          atomicInteger.wait();
						        } catch (InterruptedException e) {
							          e.printStackTrace();
						        }
					      }else{
						        try { 
							           // 偶数线程等待
							          atomicInteger.wait();
						        } catch (InterruptedException e) {
							          // TODO Auto-generated catch block
							          e.printStackTrace();
						        }
					       }
				      }
			    }
    }
  }
}

你可能感兴趣的:(java并发编程之初识线程)