Java学习日记18——多线程

本文介绍了Java中多线程的创建方式,包括继承Thread类和实现Runnable接口,并讨论了线程的同步、线程类型(普通线程与守护线程)、并发API如Atomic变量和线程池,还涉及了Timer类的使用以及Java流式操作和并行流的应用。通过实例展示了如何在Java中有效地管理和控制多线程执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java学习日记18——多线程

 线程简单来说就是在一个程序中有多个任务在执行,比如一边下载一边看剧。但是实际上是多个任务共享CPU时间片段。并非是真正的同时执行。Java支持语言级别的多线程。例如object中的wait,notify以及java.lang里的类Thread等。线程一般是在执行时间比较长的情况。

线程的创建的两种方法:

 1.通过继承Thread类创建线程,然后重写run方法来实现运行。
例如:

class Counter extends Thread {
	@Override
	public void run() {
		// TODO Auto-generated method stub
	}
}

 2.通过Thread的构造方法传递Runnable接口对象来创建线程。
例如:

class Counter implements Runnable {
	@Override
	public void run() {
		// TODO Auto-generated method stub
	}
}

无论是哪种方法都是需要重写run方法来实现,完成方法的书写后就可以创建线程对象,调用start方法启动线程。
线程生命周期
 线程的启动是用start(),线程的结束是当run方法内完成运行后自动结束。暂时停止线程执行则可以使用sleep(Time)方法进行休眠。一般sleep需要捕获异常。

线程一般分为两类:

 1.普通线程,在Java程序中,只要还有普通线程在运行,那么程序就不会结束。
 2.Daemon线程(守护线程,后台线程),如果普通线程执行完成了,后台线程就会自动终止,例如垃圾回收线程,在普通线程结束后,就自动结束运行,他不会阻止虚拟机的结束。设置收获线程使用的方法是setDaemon(true)。例如

Thread t = new MyThread();
t.setDaemon(true);
t.start();

线程的同步

 同时运行的线程需要共享数据,就必须考虑将线程的状态和行为,这是就必须要实现同步。在Java中的每一个对象都引入了互斥锁的概念,来保证数据共享操作的完整性,每个对象都有一个monitor监视器,称为互斥锁(lock,mutex)标记,保证在任意时刻,只有一个线程可以访问该对象。使用关键字synchronized用来与对象的互斥锁联系。

synchronized(对象){...}

如果对某个方法:放在声明前面

public synchronized void push(char c){...}

这样就能对代码进行原子性的控制。也就是说在执行时,整个方法是需要执行完成后才能进入另一个线程执行,避免了执行一半切换到别的线程进行,会导致数据错乱。

public class counter{
	public static void mian(String [] args){
		Num num = new Num();
		Thread counter1 = new Counter(num);
		Thread counter2 = new Counter(num);
		for (int i= 0; i <10,i++){
			num.testequals();
			try{
				Thread.sleep(100);
			}catch(InterruptedException e){
			}	
		}
	}
}
class Num{
	private int x = 0;
	private int y = 0;
	synchronized void increase(){
		x++;
		y++;
	}
	synchronized boolean testequals(){
		boolean e = (x==y);
		System.out.println(x+"="+y);
		return e;
	}
}

相应的,可以使用wait()方法实现释放对象锁,使用notify()可以恢复正在等待状态的线程。

并发API

java.util.concurrent包及其子包,从Java1.5开始。提供了一系列的工具更好更方便的使用线程。
原子变量,在java.util.concurrent.atomic包中,提供了AtomicInteger类(原子整数),以及getAndIncrement()方法(原子整数加法)。保证了同时多线程访问的安全性。在ArrayList和HashMap就是线程不安全的。所以提供了CopyOnWriteArrayList类和CopyOnWriteArraySet类和ConcurrentHashMap类和ArrayBlockingQueue类,这样的线程安全类,就不需要使用wait和notify这样的语句,会方便很多。
线程池,可以实现多个线程共用一定的资源

Timer类

在java.util.timer包中,一般是用于定时器,循环执行某件事,在javax.swing.Timer里也有timer类,可以重复执行ActionListener。

public static void main(String []args){
	Timer timer = new Timer("display");
	TimerTask task = new Mytask();
	timer.schedule(task,1000,1000);
}
class Mytask extends TimerTask{
	int n = 0;
	public void run(){
	n++;
	System.out.print(new Data());
	System.out.println("---"+n);
	}
}

运行结果如下:实现了定时任务

Sun Aug 16 17:33:57 CST 2020---25
Sun Aug 16 17:33:58 CST 2020---26
Sun Aug 16 17:33:59 CST 2020---27
Sun Aug 16 17:34:00 CST 2020---28
Sun Aug 16 17:34:01 CST 2020---29
Sun Aug 16 17:34:02 CST 2020---30

在线程中如果要更新图形化界面,则要调用SwingUtilites.invokeLater。因为在线程中不能更新界面,所以需要调用这个。

流式操作以及并行流(stream)

Java提供的一种工具,支持在流上进行函数式操作。
将数组流式化,Arrays.stream(a),然后可以进行以下操作

//函数式风格,不告诉细节,Lambda语句配合流式操作
.filter(i->i>20)//过滤流,取大于20的部分
.map(i->i*i)//映射流,把i转为i*i
.sorted()//排序
.distinct()//去掉重复的
.limit(10)//取前10个数据
.max()//取最大值
...

对于集合得到流,例如list 。可以直接使用list.stream(),将其装换为流。
并行流:将.stream()换成.parallelStream()就可以转为并行流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值