使用多线程和并发编程(一)

一.先初步了解一下基本的概念

进程:在一个操作系统中,每个独立执行的程序都可以是一个进程。

线程:一个程序至少有一个进程,一个进程至少有一个线程,java里有一个主线程和垃圾回收线程。

线程的3中创建方式:

 1.继承Thread类

 2.实现Runnable接口

 3.实现Callable接口,和Future、线程池一起使用

线程的优先级:

 优先级的返回是1-10,默认是5,数越大优先级越高。

join的作用是:

 等待该线程终止,指的是主线程等待子线程的终止。子线程调用了join方法,只有子线程执行完之后才会调用主线程。(主线程需要用到子线程的处理结果是使用join)

二.多线程之间的状态转换

状态之间装换的demo:

package cn;

public class ThreadDemo extends Thread {

	private boolean runningFlag=false;
	
	public ThreadDemo(){
		runningFlag = false;
	}
	
	public synchronized void setRunningFlag(boolean runningFlag) {
		this.runningFlag = runningFlag;  
        if(runningFlag){  
            this.notify();  
        }else{  
            try {  
                System.out.println("线程"+Thread.currentThread().getName()+"开始等待");  
                this.wait();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
	}

	@Override
	public void run() {
		sayHello();
	}
	
	//锁池状态
	public synchronized void sayHello(){
		 while(true){  
	            if(!runningFlag){  
	                try {  
	                    System.out.println("线程"+Thread.currentThread().getName()+"开始等待");  
	                    this.wait();//等待状态  
	                } catch (InterruptedException e) {  
	                    // TODO Auto-generated catch block  
	                    e.printStackTrace();  
	                }  
	            }else{  
	                try {  
	                    sleep(3000);//堵塞状态
	                    System.out.println("线程"+Thread.currentThread().getName()+"任务完成\n");    
	                    setRunningFlag(false);        //让当前线程处于等待任务状态  
	                } catch (InterruptedException e) {  
	                    e.printStackTrace();  
	                }  
	            }  
	        }  
	}
	
	
	public static void main(String[] args) {
		int i=10;
		while (i-->0) {
			//新建创建
			ThreadDemo demo=new ThreadDemo();
			demo.setName("demo"+i);
			demo.setRunningFlag(true);
			//可运行状态,start之后等待cpu获取时间片
			demo.start();
		}
		
	}
    
}

三.使用Callable接口,和Future、线程池计算1-100的和

package cn;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadAddFuture {
	public static  List<Future> futureList=new ArrayList<Future>();
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		int sum=0;
		ThreadAddFuture add=new ThreadAddFuture();
		//创建线城池
		ExecutorService pool=Executors.newFixedThreadPool(4);
		for (int i =1; i <=76;) {
			ThreadTest thread=add.new ThreadTest(i,i+24);
			//接收线程的返回值
            Future<Integer> future=pool.submit(thread);
            futureList.add(future);
            i+=25;
		}
		
		 if(futureList!=null && futureList.size()>0){
	            for(Future<Integer> future:futureList){
	               sum+=(Integer)future.get();
	            }
	        }
	        System.out.println("total result: "+sum);
	        pool.shutdown();
	}
	//实现Callable接口
	class ThreadTest implements Callable<Integer>{
		
		private int begin;		
		private int end;		
		private int sum=0;
		
		public ThreadTest(int begin,int end){
			this.begin=begin;
			this.end=end;
		}
		

		@Override
		public Integer call() throws Exception {
			for (int i =begin; i <=end; i++) {
				sum+=i;
			}
			 System.out.println("from "+Thread.currentThread().getName()+" sum="+sum);
			return sum;
		}
		
	}
}

四.使用runnable、CountDownLatch、线程池的demo

CountDownLatch:CountDownLatch是一个同步的辅助器是一个计数器,只要计数器为0主线程就可以结束堵塞进行执行,和join很像但是比join更加灵活。

package cn;

import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class WatchThread {
	
  private String name=UUID.randomUUID().toString();
  
  public void testThread() throws InterruptedException{
	  int threadNum=10;
	  //初始化countDown 
	  CountDownLatch threadSignal=new CountDownLatch(threadNum);
	  ExecutorService executor=Executors.newFixedThreadPool(threadNum);
	  for (int i = 0; i <threadNum; i++) {
		  TestThread task=new TestThread(threadSignal);
		//执行
		executor.execute(task);
	  }
	  threadSignal.await();
	  executor.shutdown();
	  System.out.println(Thread.currentThread().getName() + "+++++++结束.");  
	  
  }
  
  public static void main(String[] args) throws InterruptedException{
	  WatchThread test=new WatchThread();
	  test.testThread();
  }
  
  private class TestThread implements Runnable{
	  
	  private CountDownLatch threadsSignal;
	  
	  public TestThread(CountDownLatch threadsSignal){
		  this.threadsSignal=threadsSignal;
	  }

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "开始..." + name);  
        System.out.println("开始了线程::::" + threadsSignal.getCount());
        threadsSignal.countDown();//必须等核心处理逻辑处理完成后才可以减1  
        System.out.println(Thread.currentThread().getName() + "结束. 还有"  
                + threadsSignal.getCount() + " 个线程");  
		
	}
	  
  }
  
}

五.synchronized的实现原理

 synchronized实现同步的基础:java中的每一个对象都可以是锁,主要有3种形式:

       . 对于普通同步方法,锁的是实例对象。

       .对于静态同步方法,锁的是当前类的Class对象。

       . 对于同步代码块,锁的是括号里配置的对象。

       JVM是基于进入和退出Moniter对象来实现同步和代码块同步的,同步代码块是基于monitorenter和monitorexit实现的,同步方法ACC_synchronized实现的,monitorenter放在同步代码块的开始位置,monitorexit放在同步代码块的结束位置,必须是成对出现的。当前一个moniter被持有后,它将处于锁定状态,线程执行到moniteorenter时,获得monitor的所有权,所得对象的锁。

        synchronized获得的锁是存放在对象头里的,堆中的对象由对象头,实例变量和填充数据组成。对象头的markword存储的是HashCode、分代年龄和锁标记位,锁标记位有无锁状态、偏向锁、轻量级锁、重量级锁。对象头还会存储是否是偏向锁的标识。 

猜你喜欢

转载自www.cnblogs.com/zj-blog/p/9182939.html