java多线程的入门研究

一.多线程的核心概念

1.线程就是独立的执行路径;
2.在程序运行时,即使没有自己创建的线程,后台也会有多个线程,如主线程、gc线程
3.main()称之为主线程,为系统的入口,用于执行整个程序;
4.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密关联的,先后顺序是不能人为的关于;
5.对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
6.线程会带来额外的开销,如cpu调度时间,并发控制时间;
7.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

二.线程状态

在这里插入图片描述

线程状态:

  1. NEW:尚未启动的线程处于此状态。
  2. RUNNABLE:在java虚拟机中执行的线程处于此状态。
  3. BLOCKED:被阻塞等待监视器锁定的线程处于此状态。
  4. WAITTING:正在等待另一线程执行特定的动作线程处于此状态。
  5. TIMED_WAITTING:正在等待另一线程执行动作达到指定等待时间的线程处于此状态。
  6. TERMINATED:已退出的线程处于此状态。

线程方法:

方法说明
setPriority(int newPriority)更改线程的优先级
static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠
void join等待该线程终止
static void yield()暂停当前正在执行的线程对象,并执行其他线程(礼让)
void interrupt()中断线程,别用这个方式
boolean isAlive()测试线程是否处于活动状态

线程通信

方法名作用
wait()表示线程一直等待,直到其他线程通知,与sleep不通,会释放锁
wait(long timeout)指定等待的毫秒数
notify()唤醒一个处于等待状态的线程
notifyAll()唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度
a.停止线程(stop)
  • 不推荐使用JDK提供的stop()、destroy()方法 。【已废弃 】
  • 推荐线程自己停下来。
  • 建议使用一个标志位进行终止变量,当flag=false,则终止线程运行。

示例:线程停止代码示例

public class ThreadStop implements Runnable{

	private static boolean flag = true;
	
	
	public void run() {
		while(flag) {
			System.out.println("我在疯狂的循环中---");
		}
	}
	
	public static void main(String[] args) {
		new Thread(new ThreadStop()).start();
		for(int i = 0;i < 1000;i++) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (i == 50) {
				flag = false;
			}
		}
	}
}
b.线程休眠(sleep)
  • sleep(时间)指定当前线程阻塞的毫秒数;
  • sleep存在异常InterruptedException;
  • sleep时间达到后线程进入就绪状态;
  • sleep可以模拟网络延时,倒计时等;
  • 每一个对象都有一个锁,sleep不会释放锁;
c.线程礼让(yield)
  • 礼让线程,让当前正在执行的线程暂停,但不阻塞;
  • 让线程从运行状态转为就绪状态;
  • 让cpu重新调度,礼让不一定成功!看cpu心情;
d.线程插队(Join)
  • Join合并线程,待此线程执行完成后,在执行其他线程,其他线程阻塞
  • 可以想象成插队
public class ThreadJoin implements Runnable{

	public static void main(String[] args) {
		Thread t = new Thread(new ThreadJoin());
		t.start();
		for (int i = 0; i < 500; i++) {
			if (i == 20) {
				try {
					t.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println("普通客户:"+i);
		}
	}
	
	
	public void run() {
		
		for (int i = 0; i < 100; i++) {
			System.out.println("线程VIP:"+i);
		}
		
	}
}
e.线程的优先级
  • java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
  • 线程的优先级用数字表示,范围从1~10
    • Thread.MIN_PRIORITY = 1;
    • Thread.MAX_PRIORITY = 10;
    • Thread.NORM_PRIORITY = 5;
  • 使用以下方式改变或获取优先级
    • getPriority()
    • setPriority(int xxx)
f.守护(daemon)线程
  • 线程分为用户线程和守护线程(mian()线程代表用户线程,gc()代表守护线程)
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  • 如:后台记录操作日志,监控内存,垃圾回收等待…
public class ThreadDaemon{
	
   public static void main(String[] args) {
	   // 打开守护线程
		God god = new God();
		Thread t = new Thread(god);
		t.setDaemon(true);// true:代表开始守护线程,false:默认,代表用户线程
		t.start();
		new Thread(new People()).start();
   }
}

class God implements Runnable{

	public void run() {
		while(true) {
			System.out.println("---上帝在保护着你----");
		}
	}
	
}

class People implements Runnable {

	@Override
	public void run() {
		for(int i = 0;i < 50;i++) {
			System.out.println("----人民在快乐的生活着---");
		}
	}
	
}

三.多线程的三种创建方式

  1. extends Thread类;
  2. implements Runnable接口;
  3. implements Callable接口;

例1:extends Thread类

public class Thread1 extends Thread{
		private String name;
		
		public Thread1 (String name) {
			this.name = name;
		}
		
		public void run() {
	
			while(true) {
				System.out.println("我是一个兔子---");
			}
		}
		
		public static void main(String[] args) {
			new Thread1("张三").start();
		}
	}

例2: implements Runnable接口;

public class Thread2 implements Runnable{
		private String name;
		
		public Thread2 (String name) {
			this.name = name;
		}
		
		public Thread2() {
		}
	
		public void run() {
			while(true) {
				name = Thread.currentThread().getName();
				if(name.equals("张三")) {
					for(int i = 0;i < 100;i++) {
						System.out.println("---我是张三-"+i);
					}
					break;
				}
				
				if(name.equals("李四")) {
					for(int i = 0;i < 100;i++) {
						System.out.println("---我是李四-"+i);
					}
					break;
				}
			}
		}
		
		
		public static void main(String[] args) {
			Thread2 t = new Thread2();
			new Thread(t,"张三").start();
			new Thread(t,"李四").start();
		}
 	}

例3:implements Callable接口

public class Thread3 implements Callable<Boolean>{

			private String name;
			
			public Thread3 (String name) {
				this.name = name;
			}
			
			public Thread3() {
			}
		
			public Boolean call() {
				System.out.println("--"+name);
				return true;
			}
			
			public static void main(String[] args) throws InterruptedException, ExecutionException {
				
				Thread3 t1 = new Thread3("张三");
				Thread3 t2 = new Thread3("李四");
				Thread3 t3 = new Thread3("王五");
				// 1.创建执行服务
				ExecutorService ex = Executors.newFixedThreadPool(3);
				// 2.提交执行
				Future<Boolean> r1 = ex.submit(t1);
				Future<Boolean> r2 = ex.submit(t2);
				Future<Boolean> r3 = ex.submit(t3);
				// 获取结果
				boolean rs1 = r1.get();
				boolean rs2 = r2.get();
				boolean rs3 = r3.get();
				// 关闭服务
				ex.shutdownNow();
			}
	}

四.多线程其他扩展

a.多线程之Lambda表达式
  • Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法
  • 语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)

代码示例:

for (int i = 0;i < 10000;i++) {
			new Thread(
					// lambda表达式
					()->{
						list.add(Thread.currentThread().getName());
					}
					).start(); 
		}
}
b.多线程之ReentrantLock
public class ThreadLock implements Runnable{

	public static void main(String[] args) {
		ThreadLock t2 = new ThreadLock();
		new Thread(t2).start();
		new Thread(t2).start();
		new Thread(t2).start();
		new Thread(t2).start();
		new Thread(t2).start();
		new Thread(t2).start();
	}
	
	private int ticketNums = 10;
	
	final transient ReentrantLock lock = new ReentrantLock();
	
	@Override
	public void run() {
		while(true) {
			
			try {
				lock.lock();
				if (ticketNums <= 0) {
					break;
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(ticketNums--);
			} finally {
				lock.unlock();
			}
		}
	}
}
c.多线程之JUC

1.CopyOnWriteArrayList

public class ThreadJucList {

	public static void main(String[] args) {
		// 理论上线程安全,实际存在删除操作的时候会存在数组越界的风险,固不是绝对的安全
		CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
		for (int i = 0;i < 10000;i++) {
			new Thread(
					// lamda表达式
					()->{
						list.add(Thread.currentThread().getName());
					}
					).start(); 
		}
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("------list-size:"+list.size());
	}
}
d.管程法
/**
 * 测试:生产者消费者模型--》利用缓冲区解决:管程法
 * 生产者、消费者、产品、缓冲区
 */
public class ThreadContainer {
	public static void main(String[] args) {
		SynContainer syn = new SynContainer();
		new Thread(new Productor(syn)).start();
		new Thread(new Consumer(syn)).start();
	}
	
}
// 缓冲区
class SynContainer{
	// 设置容器的大小
	Chicken[] chickens = new Chicken[2];
	// 容器的计数器
	int count = 0;
	//生产者放入产品
	public synchronized void push(Chicken chicken) {
		// 如果容器满了,就需要等待消费者消费
		if (count == chickens.length) {
			// 通知消费者消费,等待生产
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 如果没有满,我们就需要丢入产品
		chickens[count] = chicken;
		count++;
		// 可以通知消费者消费了
		this.notifyAll();
	}
	// 消费者消费产品
	public synchronized Chicken pop() {
		// 判断能否消费
		if (count == 0) {
			// 等待生产者生产,消费者等待
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//如果可以消费
		count--;
		Chicken chicken = chickens[count];
		// 吃完了,通知生产者生产
		this.notifyAll();
		return chicken;
	}
}
// 生产者
class Productor implements Runnable{
	SynContainer container;
	public Productor(SynContainer container) {
		this.container = container;
	}
	
	@Override
	public void run() {
		for (int i = 0;i < 10;i++) {
			System.out.println("----生产者生产了-->"+i+"的鸡");
			container.push(new Chicken(i));
			
		}
	}
}
// 消费者
class Consumer implements Runnable{
	SynContainer container;
	public Consumer(SynContainer container){
		this.container = container;
	}
	@Override
	public void run() {
		for(int i = 0;i < 10;i++) {
			System.out.println("---消费者消费了-->"+container.pop().numNo+"的鸡");
		}
	}
}
// 产品
class Chicken{
	int numNo;
	public Chicken(int numNo) {
		this.numNo = numNo;
	}
}
e.使用Runnable创建线程池
/**
 * 使用线程池--Runnable
 */
public class ThreadPool implements Runnable{

	public static void main(String[] args) {
		// 1.创建服务,创建线程池
		ExecutorService service = Executors.newFixedThreadPool(10);
		// 2.执行
		service.execute(new ThreadPool());
		service.execute(new ThreadPool());
		service.execute(new ThreadPool());
		service.execute(new ThreadPool());
		service.execute(new ThreadPool());
		// 3.关闭链接
		service.shutdown();
	}
	
	@Override
	public void run() {
		System.out.println("---我是线程池:"+Thread.currentThread().getName());
	}
	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜家小型男

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值