java 并发之线程

5 篇文章 0 订阅

现代的操作系统都是每运行一个程序就会为其创建一个进程(Process),进程具有独立性,动态性和并发性的特点。,在操作系统中可以支持多个进程并发地执行,比如一边编程,一边听歌…
多线程则是对多进程的扩展,线程被称作轻量级进程(Light Weight Process),一个进程可以拥有多个线程,这些线程拥有独立的程序计数器,堆栈和局部变量等等,可以并发执行。因此,线程是现代操作系统调度的最小单元。

优势

  1. 更大程度地利用计算机处理器
    一个线程在一个时刻只能运行在一个处理器核心上,现代计算机处理器核心数量越来越多,如果采用多线程技术,将程序的计算逻辑分配到多个处理器核心上,会显著减少程序的处理时间。
  2. 缩短程序响应时间
    针对数据一致性不是很强的业务,可以将部分逻辑交给线程处理,需要立即响应给用户的程序可以很快的执行完成,缩短了响应时间,提高了程序的体验感
  3. 更好的编程模型
    java 内置了对多线程的支持,提供了良好的,考究并且一致的编程模型,极大地简化了多线程的开发。

创建线程

  1. 继承 Thread 类创建线程类
public class ThreadExample extends Thread {
	
	/**
	* ①重写 run 方法
	**/
	@Override
	public void run() {
		System.out.println("执行线程");
	}

	public static void main(String[] args) {
		// ②创建子类的实例对象
		ThreadExample threadExample = new ThreadExample();
		// ③调用 start 方法启动线程
		threadExample.start();
	}
}
  1. 实现 Runnable 接口创建线程类
public class RunnableExample implements Runnable {

	/**
	 * ①实现 Runnable 接口的 run 方法
	 */
	@Override
	public void run() {
		System.out.println("执行线程");
	}
	
	public static void main(String[] args) {
		// ②创建实现实例
		RunnableExample runnableExample = new RunnableExample();
		// ③将实例作为 Thread 的 target 来创建 Thread 对象
		Thread thread = new Thread(runnableExample);
		// ④调用 start 方法启动线程
		thread.start();
	}

}
  1. 使用 Callable 和 Future 创建线程
    callable 接口提供了 call 方法作为线程的执行体,该方法可以具有返回值,可以声明和抛出异常
public class FutureExample implements Callable<String> {

	/**
	 * ①实现 Callable 接口的 call 方法
	 */
	@Override
	public String call() throws Exception {
		// 执行线程逻辑
		System.out.println("执行线程");
		//返回结果
		return "a";
	}
	
	public static void main(String[] args) {
		// ②创建 Callable 对象
		FutureExample futureExample= new FutureExample();
		// ③使用 FutureTask 类包装 Callable 对象
		FutureTask<String> futureTask = new FutureTask<>(futureExample);
		// ④使用 FutureTask 对象作为 target 创建 Thread
		Thread thread = new Thread(futureTask);
		// ⑤调用 start 方法启动线程
		thread.start();
		try {
			// ⑥获取返回值
			System.out.println(futureTask.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}

}

线程的状态

  1. 新建状态 :通过 new 关键字创建的线程,还未被调用 start 方法时处于新建状态;
  2. 运行状态:线程开始执行run方法或者call方法的线程执行体,处于运行状态;
  3. 阻塞状态:当线程遇到等待阻塞于锁、调用了 sleep 方法等等情况时,线程就处于阻塞状态;
  4. 就绪状态(等待或者超时等待状态):线程调用了start方法却未执行 run 方法,或者线程在等待一个锁的释放,获取锁,这时候线程处于就绪状态;
  5. 终止状态:线程执行完毕,则线程进入终止状态。

线程通信

在实际开发过程中,不可能让所有的线程都可以孤立地运行,线程之间通过相互配合来完成工作,这样才更有价值。

volatile 和 synchronized 关键字

java 支持多个线程同时访问一个对象,由于每个线程本地都有这个变量的拷贝,所以在执行的过程中,每个线程所获取到的变量不一定是最新的。
使用关键字 volatile 修饰的变量,在任一线程中被访问时,规定必须从共享内存中获取;在任一线程中被更新时,规定必须同步刷新回共享内存。
关键字 synchronized 可以修饰方法或者以同步代码块的形式使用,确保了多个线程在同一时刻,只能有一个线程处于同步方法或者同步代码块中,保证了线程对变量访问的可见性和排他性。

等待/通知机制

方法名称描述
notify()通知一个在对象上等待的线程,使其从wait 方法返回,继续执行线程体
notifyAll()通知在对象上等待的所有线程
wait()线程进入就绪状态(会释放对象的锁)
wait(long l)超时等待一段时间,没有收到通知就超时返回
wait(long l, int i)超时等待(控制等待时间的单位【纳秒,毫秒等等】)

等待/通知指的是,一个线程A调用了一个对象的 wait 方法,进入等待就绪状态,另一个线程B在调用了同一个对象的notify()或者notifyAll()方法后线程A接收到通知从 wait方法返回,进而执行后续操作。

代码示例

public class NotifyExample {
	
	static boolean flag = true;
	static Object obj = new Object();
	
	
	public static void main(String[] args) {
		// 启动两个线程
		Thread waitThread = new Thread(new Wait());
		waitThread.start();
		Thread notifyThread = new Thread(new Notify());
		notifyThread.start();
	}
	
	static class Wait implements Runnable{

		@Override
		public void run() {
			// 获取 obj 的锁
			synchronized(obj) {
				while(flag) {
					// 满足条件进入等待
					System.out.println("开始等待");
					try {
						obj.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				// 不满足条件开始工作
				System.out.println("wait 线程工作中");
			}
			
		}
		
	}
	
	static class Notify implements Runnable{

		@Override
		public void run() {
			// 获取  obj 的锁
			synchronized(obj) {
				// 修改条件并发起通知
				flag = false;
				System.out.println("通知其他线程");
				obj.notifyAll();
			}
			
			// 再次获取锁
			synchronized(obj) {
				System.out.println("再次获取锁");
			}
			
		}
		
	}

}

运行结果有两种:
在这里插入图片描述
在这里插入图片描述

  1. 使用wait(),notify()或者nitifyAll()前需要对对象加锁;
  2. 在wait()调用完之后,线程状态由运行状态转换为就绪状态并被放置到对象的等待队列;
  3. notify()或者nitifyAll()调用完之后,等待线程不会立即从wait()返回,而是等到调用notify()或者nitifyAll()的线程释放锁之后,才有机会返回;
  4. notify()将等待队列中的一个线程移动到同步队列,notifyAll()将等待队列中的所有线程移动到同步队列,被移动的线程进入阻塞状态;
  5. 从wait()方法返回的前提是获得了调用对象的锁。

join

thread.join() 方法可以控制当前线程等待thread线程终止之后再继续执行thread.join()后面的代码。

线程变量

线程变量 ThreadLocal 是一个以 ThreadLocal 对象为键、任意对象为值的存储结构。这个结构附带在线程上,线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。

代码示例:

public class ThreadLocalExample {
	
	private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<Long>();
	
	public static final void countBegin() {
		TIME_THREADLOCAL.set(System.currentTimeMillis());
	}
	
	public static final long countResult() {
		return System.currentTimeMillis() - TIME_THREADLOCAL.get();
	}
	
	public static void main(String[] args) throws Exception {
		ThreadLocalExample.countBegin();
		TimeUnit.SECONDS.sleep(1);
		System.out.println("运行程序总共花费" + ThreadLocalExample.countResult() + "毫秒");
	}

}

运行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以通过以下几种方式实现多线程并发: 1. 继承Thread类:创建一个新的类,并继承Thread类,重写run()方法,在run()方法中编写该线程的执行逻辑。然后创建该类的实例,并调用start()方法启动线程。 ```java class MyThread extends Thread { public void run() { // 线程执行逻辑 } } public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } } ``` 2. 实现Runnable接口:创建一个实现Runnable接口的类,实现其run()方法,在run()方法中编写该线程的执行逻辑。然后创建该类的实例并传入Thread的构造函数中,最后调用start()方法启动线程。 ```java class MyRunnable implements Runnable { public void run() { // 线程执行逻辑 } } public class Main { public static void main(String[] args) { MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); } } ``` 3. 使用Executor框架:Java提供了Executor框架来管理和控制线程的执行。可以使用ThreadPoolExecutor或ScheduledThreadPoolExecutor来创建线程池,并通过submit()方法提交任务。 ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { Runnable worker = new MyRunnable(); executor.execute(worker); } executor.shutdown(); } } ``` 以上是Java中实现多线程并发的几种常见方式。根据具体的需求和场景,选择适合的方式来实现多线程并发

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值