欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深入浅出java多线程

程序员文章站 2022-06-21 15:06:13
...

 

一.多线程的第一种实现方式

    继承Thread类

public class MyThread extends Thread {

	public void run() {
		for(int i=0;i<67;i++) {
			System.out.println(getName()+" "+i);
		}
	}
}

 

二.多线程的第二种实现方式

实现Runnable接口

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		for(int i=0;i<67;i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+" "+i);
		}
		//用Tread类来获取当前线程对象比较简单,直接用this就可以
		//用Runnable接口就需要使用Tread.currentThread()
		
		//继承方式,直接创建Thread子类对象
		//实现Runnable接口创建的对象只能作为线程对象的target

	}

}

 

三.Tread类中的一些常用方法

1.public final void join():等待该线程终止
 为什么要用join()方法
 在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,
 主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,
 也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
 

public static void main(String[]args) {
		Threadjoin m1=new Threadjoin();
		Threadjoin m2=new Threadjoin();
		m1.start();
		try {
			m1.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		m2.start();
		
	}
public void run() {
		for(int i=0;i<67;i++) {
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(getName()+" "+i);
		}
	}

 

2.yield

sleep()和yield()的区别
     (1)sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行;
      yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到
       可执行状态后马上又被执行。
     (2)sleep 方法使当前运行中的线程睡眼一段时间,进入不可运行状态,这段时间的长短是
     由程序设定的,yield 方法使当前线程让出 CPU 占有权,但让出的时间是不可设定的。
     实际上,yield()方法对应了如下操作:先检测当前是否有相同优先级的线程处于同可运行状态,
     如有,则把 CPU  的占有权交给此线程,否则,继续运行原来的线程。
     所以yield()方法称为“退让”,它把运行机会让给了同等优先级的其他线程
   (3)sleep 方法允许较低优先级的线程获得运行机会,但 yield()  方法执行时,
   当前线程仍处在可运行状态,所以,不可能让出较低优先级的线程些时获得 CPU 占有权。
   在一个运行系统中,如果较高优先级的线程没有调用 sleep 方法,又没有受到 I\O 阻塞,
   那么,较低优先级线程只能等待所有较高优先级的线程运行结束,才有机会运行。
 

public void run() {
		for(int i=1;i<88;i++) {
			System.out.println(getName()+" "+i);
		}
		Thread.yield();
	}

 

3.Deaaemon

public final void setDaemon(boolean on) :true时,表示为守护线程
  将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
 守护线程不会立即结束掉,它会执行一段时间在结束掉)

该方法必须在启动线程前调用。

	public static void main(String[]args) {
		 TreadDaemon t1=new  TreadDaemon();
		 TreadDaemon t2=new  TreadDaemon();
		 t1.setDaemon(true);
		 t2.setDaemon(true);
		 t1.start();
		 t2.start();
		 
		 Thread.currentThread().setName("刘备");
			for(int x =0 ; x < 5 ; x ++) {
				System.out.println(Thread.currentThread().getName()+":"+x);
			}
	}

 

三.模拟电影院卖票模式

1.

/**
 * 模拟电影院卖票
 * 实现多线程 方式一
 * */
public class test {

	public static void main(String[]args) {
		ticket t1=new ticket();
		ticket t2=new ticket();
		ticket t3=new ticket();
		//给各个线程起名字
		t1.setName("窗口1");
		t2.setName("窗口2");
		t3.setName("窗口3");
		//启动线程
		t1.start();
		t2.start();
		t3.start();
		
	}
}
public class ticket extends Thread{

	private static int ticket=100;
	public void run() {
		while(true) {
			if(ticket>0) {
				System.out.println(getName()+"正在售出第"+(ticket--)+"张票");
			}else {
				System.exit(0);
			}
		}
	}
}


2.

/**
 * 模拟电影院卖票
 * 实现多线程  方式二
 * */
public class test {

	public static void main(String[]args) {
		seilTicket s=new seilTicket();
		
		Thread t1=new Thread(s,"窗口1");
		Thread t2=new Thread(s,"窗口2");
		Thread t3=new Thread(s,"窗口3");
		//启动线程
		t1.start();
		t2.start();
		t3.start();
	}
}

 

public class seilTicket implements Runnable {

	private static int tickets=100;
	@Override
	public void run() {
		
		while(true) {
			if(tickets>0) {
				System.out.println(Thread.currentThread().getName()+"正在售出第"
						+(tickets--)+"张票");
			}else {
				System.exit(0);
			}
		}

	}

}

 


3. 模拟电影院卖票
 加入睡眠,更符合实际情况,卖票系统会有延时
  如果没有加入同步代码块,则会引起卖出负票,零票,以及一张票被卖出多次
     这是由于CPU的执行有一个特点(具有原子性操作:最简单最基本的操作)
      t1线程进来,睡完了,100张票
      原子性操作:记录以前的值
      接着tickets-- :票变成99张票
     在马上输出99张票之前,t2/t3进来,直接输出记录的以前那个tickets的值
      出现:
       窗口1正在出售第100张票
       窗口3正在出售第99张票
       窗口2正在出售第99张票
      
      原子性操作
      
  
 引入同步代码块synchronized

 

	public static void main(String[]args) {
		seil s=new seil();
		
		Thread t1=new Thread(s,"窗口1");
		Thread t2=new Thread(s,"窗口2");
		Thread t3=new Thread(s,"窗口3");
		
		t1.start();
		t2.start();
		t3.start();
	}
public class seil implements Runnable {

	private static int tickets=100;
	//同一个锁对象
	private Object o=new Object();
	@Override
	public void run() {
		while(true) {
			//同步代码块
			synchronized(o){//这就相当于一个线程执行到该对象的synchronized方法时,
							//就为这个对象加上了一把锁,锁住了这个对象,
							//别的线程在调用该方法时,发现了这把锁以后就继续等待下去了。
				if(tickets>0) {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
					System.out.println(Thread.currentThread().getName()
							+"正在售出第"+(tickets--)+"张票");
				}else {
					System.exit(0);
				}
			}
		}

	}

}

synchronized关键字是一个修饰符,可以修饰方法或代码块,其的作用就是,对于同一个对象
   (不是一个类的不同对象), 当多个线程都同时调用该方法或代码块时,必须依次执行,也就是说,
   如果两个或两个以上的线程同时执行该段代码时,如果一个线程已经开始执行该段代码,
  则另 外一个线程必须等待这个线程执行完这段代码才能开始执行。

 

 

 

 

 

 

4.静态同步方法

 

public class seil implements Runnable {

	private static int tickets=100;
	private Object o=new Object();
	int x=0;
	@Override
	public void run() {
		while(true) {
			if(x%2==0) {
				synchronized(seilTicket.class) {
					if(tickets>0) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()
								+"正在售出第"+(tickets--)+"张票");
					}else {
						System.exit(0);
					}
				}
			}else {
				seilTickets();
			}
			x++;
		}

	}
	//静态同步方法
	public synchronized static void seilTickets() {
		if(tickets>0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()
					+"正在售出第"+(tickets--)+"张票");
		}else {
			System.exit(0);
		}
	}

}

 

四.lock

 

public static void main(String[]args) {
		seil s=new seil();
		
		Thread t1=new Thread(s,"窗口1");
		Thread t2=new Thread(s,"窗口2");
		Thread t3=new Thread(s,"窗口3");
		
		t1.start();
		t2.start();
		t3.start();
	}
public class seil implements Runnable {

	private static int tickets=100;
	//创建Lock接口对象
	 private Lock lock=new ReentrantLock();
	
	@Override
	public void run() {
		while(true) {
			try {
				lock.lock();//获取锁
				if(tickets>0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()
							+"正在售出第"+(tickets--)+"张票");
				}else {
					System.exit(0);
				}
				
			}finally {
				if(lock!=null) {
					//释放锁
					lock.unlock();
				}
			}
		}

	}

}

 

五.消费者生产者模式

1.
 

public static void main(String[]args) {
		student ss=new student();
		setStudent s=new setStudent(ss);
		getStudent g=new getStudent(ss);
		
		Thread d1=new Thread(s);
		Thread d2=new Thread(g);
		
		d1.start();
		d2.start();
		
		
	}
public class setStudent implements Runnable {

	private student s;
	
	public setStudent(student s) {
		super();
		this.s = s;
	}

	@Override
	public void run() {
		s.name="卜凡";
		s.age=22;
	}

}

 

public class getStudent implements Runnable {

	private student s;
	
	
	public getStudent(student s) {
		super();
		this.s = s;
	}


	@Override
	public void run() {
		System.out.println(s.name+" "+s.age);
	}

}

 

public class student {

	String name;
	int age;
}

2.

public static void main(String[]args) {
		student ss=new student();
		setStudent s=new setStudent(ss);
		getStudent g=new getStudent(ss);
		
		Thread d1=new Thread(s);
		Thread d2=new Thread(g);
		
		d1.start();
		d2.start();
		
}

 

public class setStudent implements Runnable {

	private student s;
	
	public setStudent(student s) {
		super();
		this.s = s;
	}
	
	private int x=0;
	/**
	 * 1)是否是多线程环境		是
 		2)是否有功共享数据		是
 		3)是否有多条语句对共享数据进行操作 	有
 			
 		同步机制(同步代码块/同步方法)
	 * */
	@Override
	public void run() {
		while(true) {
			synchronized(s) {//加入同步代码块
				if(x%2==0) {
					s.name="卜凡";
					s.age=22;
				}else {
					s.name="王子异";
					s.age=23;
				}
				x++;
			}
		}

	}

}

 

public class getStudent implements Runnable {

	private student s;
	
	public getStudent(student s) {
		super();
		this.s = s;
	}

	@Override
	public void run() {
		while(true) {
			System.out.println(s.name+" "+s.age);
		}

	}

}

 

public class student {
	String name;
	int age;
}


六.等待唤醒机制

public static void main(String[]args) {
		student ss=new student();
		setStudent s=new setStudent(ss);
		getStudent g=new getStudent(ss);
		
		Thread d1=new Thread(s);
		Thread d2=new Thread(g);
		
		d1.start();
		d2.start();

 

//生产者线程
public class setStudent implements Runnable {

	private student s;
	
	public setStudent(student s) {
		super();
		this.s = s;
	}

	private int x=0;
	@Override
	public void run() {
		while(true) {
			synchronized(s) {
				//资源类有数据,则生产者等待消费者消费,暂时不进行生产
				if(s.flag) {
					try {
						s.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				//资源类没有数据了,则生产者进行生产
				if(x%2==0) {
					s.name="卜凡";
					s.age=22;
				}else {
					s.name="王子异";
					s.age=23;
				}
				x++;
				//产生数据后,将flag的值改变为true
				s.flag=true;
				//通知消费者消费
				s.notify();//唤醒后,t1,t2都互相等待
			}
		}
	}

}

 

//消费者线程
public class getStudent implements Runnable {

	private student s;
	
	public getStudent(student s) {
		super();
		this.s = s;
	}

	@Override
	public void run() {
		while(true) {
			synchronized(s) {
				//资源类没有数据了
				//消费者等待
				if(!s.flag) {
					try {
						s.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					//资源类有数据,则消费者输出
					System.out.println(s.name+" "+s.age);
					//资源消费完了,将flag置为false
					//通知生产者没有数据了,让生产者生产数据
					s.flag=false;
					s.notify();
				}
			}
		}

	}

}

 

//资源类
public class student {

	String name;
	int age;
	boolean flag;
}


七.线程组

线程组是一个线程的集合,线程组也可以包含其他线程组

public static void main(String[]args) {
		ThreadGroup tp=new ThreadGroup("新的线程组");
		MyThread m=new MyThread();
		
		Thread t1=new Thread(tp,m,"线程1");
		Thread t2=new Thread(tp,m,"线程2");
		
		t1.start();
		t2.start();
		
		System.out.println(t1.getThreadGroup().getName());
		System.out.println(t2.getThreadGroup().getName());
		
	}

 

public class MyThread implements Runnable{

	@Override
	public void run() {
		for(int i=0;i<67;i++) {
			System.out.println(Thread.currentThread().getName()+" "+i);
		}
		
	}

	
}


八.线程池

1.线程池

 

	public static void main(String[]args) {
		ExecutorService pool = Executors.newFixedThreadPool(2);
		pool.submit(new MyRunnable());
		pool.submit(new MyRunnable());
		pool.shutdown();
		
	}

 

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		for(int i=0;i<97;i++) {
			System.out.println(Thread.currentThread().getName()+" "+i);
		}

	}

}

 

 

2.future

private static Future<Integer> future;

	public static void main(String[]args) throws InterruptedException, ExecutionException {
		//创建线程池对象
		ExecutorService pool = Executors.newFixedThreadPool(2);
		//提交任务
		Future<Integer> f1=  pool.submit(new MyCallable(100));
		Future<Integer> f2=  pool.submit(new MyCallable(200));
		
		//获取结果
		Integer i1=f1.get();
		Integer i2=f2.get();
		System.out.println(i1);
		System.out.println(i2);
		
		//关闭线程池
		pool.shutdown();
		
	}

 

public class MyCallable implements Callable<Integer> {

	private int num;
	
	public MyCallable(int num) {
		super();
		this.num = num;
	}

	@Override
	public Integer call() throws Exception {
		int sum=0;
		for(int i=0;i<num;i++) {
			sum+=i;
		}
		
		return sum;
	}

}

 

 

 

九.多线程的第三种实现方式

多线程实现方式第三种:
 
  前提:自定义类实现Callable接口
   1)创建线程池对象: Executors 里面的那个方法,返回的是ExecutorsService
   2) 然后调用ExecutorsService里面的提交任务的方法:
  <T> Future<T> submit(Callable<T> task)提交一个返回值的任务用于执行
   3)关闭线程池

public static void main(String[]args) {
		//创建线程池对象
		ExecutorService pool = Executors.newFixedThreadPool(2);
		//调用提交方法
		pool.submit(new MyCallable());
		pool.submit(new MyCallable());
		
		pool.shutdown();
		
	}

 

public class MyCallable implements Callable {

	@Override
	public Object call() throws Exception {
		for(int i=0;i<97;i++) {
			System.out.println(Thread.currentThread().getName()+" "+i);
		}
		return null;
	}

}