1.创建线程
1.1 继承Thread类
NewThreadExtend
public class NewThreadExtend extends Thread {
public NewThreadExtend(String name) {
super(name);
}
@Override
public void run() {
while (!interrupted()) {//和interrupt();搭配使用
System.out.println(getName() + "线程执行了 .. ");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
NewThreadExtend d1 = new NewThreadExtend("first-thread");
NewThreadExtend d2 = new NewThreadExtend("second-thread");
d1.setDaemon(true);//守护线程
d1.start();
d2.start();
// d1.stop(); //已过期.
d1.interrupt();//JDK6才出现
}
}
NewThreadExtendAndDaemon(守护线程)
public class NewThreadExtendAndDaemon extends Thread {
public NewThreadExtendAndDaemon(String name) {
super(name);
}
@Override
public void run() {
while(true) {
System.out.println(getName() + "线程执行了 .. ");
}
}
public static void main(String[] args) {
NewThreadExtendAndDaemon d1 = new NewThreadExtendAndDaemon("first-thread");
NewThreadExtendAndDaemon d2 = new NewThreadExtendAndDaemon("second-thread");
d1.setDaemon(true);//守护线程
d2.setDaemon(true);//守护线程
d1.start();
d2.start();
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
}
}
NewThreadExtendAndInterrupt
public class NewThreadExtendAndInterrupt extends Thread {
public NewThreadExtendAndInterrupt(String name) {
super(name);
}
@Override
public void run() {
while (!interrupted()) {//和interrupt();搭配使用
System.out.println(getName() + "线程执行了 .. ");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
NewThreadExtendAndInterrupt d1 = new NewThreadExtendAndInterrupt("first-thread");
NewThreadExtendAndInterrupt d2 = new NewThreadExtendAndInterrupt("second-thread");
d1.start();
d2.start();
d1.interrupt();//JDK6才出现
}
}
NewThreadExtendAndStop
public class NewThreadExtendAndStop extends Thread {
public NewThreadExtendAndStop(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "线程执行了 .. ");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
NewThreadExtendAndStop d1 = new NewThreadExtendAndStop("first-thread");
NewThreadExtendAndStop d2 = new NewThreadExtendAndStop("second-thread");
d1.start();
d2.start();
d1.stop(); //已过期( @Deprecated).
}
}
1.2 实现Runnable接口
/**
* 作为线程任务存在
*/
public class NewThreadRunnable implements Runnable {
@Override
public void run() {
while(true) {
System.out.println("thread running ...");
}
}
public static void main(String[] args) {
Thread thread = new Thread(new NewThreadRunnable());
thread.start();
}
}
以上两种都需要覆盖run()方法,但是继承只能继承一个父类,使用接口的方式解耦,更灵活.
Java中Runnable和Thread的区别
1.3 匿名内部类的方式
只运行一次的时候更简单实用
public class NewThreadAnonymousInner {
/**
anonymous1 extend thread start ..
anonymous2 Runnable thread start ..
anonymous1and2 extend thread start ..
*/
public static void main(String[] args) {
anonymous1();
anonymous2();
anonymous1and2();
}
//继承Thread覆盖方式
public static void anonymous1() {
//(子类继承覆盖方法,{}即可)
new Thread(){
@Override
public void run() {
super.run();
}
}.start();
}
//实现Runnable覆盖方式
public static void anonymous2() {
//传参的位置new对象是 implement的简写方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("anonymous2 Runnable thread start ..");
}
}).start();
}
//继承Thread(子)覆盖并且实现Runnable覆盖方式(父的target),子覆盖父的
//runnable的run也是传给thread,最后被thread的run覆盖
public static void anonymous1and2() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("anonymous1and2 Runnable thread start ..");
}
}) {
public void run() {
System.out.println("anonymous1and2 extend thread start .. ");
};
}.start();
}
}
//运行结果
anonymous1 extend thread start ..
anonymous2 Runnable thread start ..
anonymous1and2 extend thread start ..
1.4 带返回值的线程Callable
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
//传入的是Integer类型,返回的就是Integer类型
public class NewThreadCallable implements Callable<Integer> {
//类似run方法
@Override
public Integer call() throws Exception {
System.out.println("正在进行紧张的计算....");
Thread.sleep(3000);
return 1;
}
public static void main(String[] args) throws Exception {
NewThreadCallable threadCallable = new NewThreadCallable();
FutureTask<Integer> task = new FutureTask<>(threadCallable);
Thread t = new Thread(task);
t.start();//启动的时候则call()开始执行了
System.out.println("我先干点别的。。。");
Integer result = task.get();
System.out.println("线程执行的结果为:" + result);
}
}
1.5 定时器
import java.util.Timer;
import java.util.TimerTask;
public class ThreadTimerTask {
public static void main(String[] args) {
Timer timer = new Timer();
//源码:public abstract class TimerTask implements Runnable
timer.schedule(new TimerTask() {
@Override
public void run() {
// 实现定时任务
System.out.println("timertask is run");
}
}, 0, 1000);
}
}
另有quartz可用.
1.6 线程池的实现
public class NewThreadPool {
public static void main(String[] args) {
//固定线程池
ExecutorService threadPool1 = Executors.newFixedThreadPool(10);
//长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
ExecutorService threadPool2 = Executors.newCachedThreadPool();
for (int i = 0; i < 1000; i++) {
threadPool1.execute(new Runnable() {
@Override
public void run() {
System.out.println("threadPool1->"+Thread.currentThread().getName());
}
});
}
threadPool1.shutdown();
for(int i=0;i<1000;i++){
threadPool2.execute(
new Runnable() {
@Override
public void run() {
System.out.println("threadPool2->"+Thread.currentThread().getName());
}
}
);
}
}
}
Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor
1.7 Spring实现多线程
- @Async
@Async
method注解
Spring Boot系列二 Spring @Async异步线程池用法总结
3.8 Lambda表达式实现
代码简洁,实现更方便,并发支持好,代码性能高,
public class LambdaThread {
public static void main(String[] args) {
List<Integer> values = Arrays.asList(10, 20, 30, 40);
int res = new LambdaThread().add(values);
System.out.println("计算的结果为:" + res);
}
public int add(List<Integer> values) {
//values.parallelStream().mapToInt(i->i).sum();//集合数据相加
//values.stream().forEach(System.out :: println);//会发现打印结果为按照顺序的,且每次一样
values.parallelStream().forEach(System.out :: println);//会发现打印结果为无序的,且每次不一样.说明并行
//values.parallelStream().forEachOrdered(System.out :: println);//如果要并行计算有序
//根据value的类型,自动猜测类型为Integer
return values.parallelStream().mapToInt(i -> i * 2).sum();
}
}
1.8 Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
总结:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
1.9 注意
- main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。
- 在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM就是在操作系统中启动了一个进程。
2.多线程风险
2.1 活跃性问题
2.1.1 死锁
哲学家就餐,资源相互需要,互占用,互不释放.
jconsole选中进程,然后进入线程,有按钮操作"检测死锁"来查看死锁情况.
cmd->jsoncole->选择进程-->线程-->检测死锁
2.1.2 饥饿
餐厅排队吃饭,一窗口,新来就插队,还不走,有一个一直排不上,就饥饿,优先级造成的.
产生原因:
高优先级吞噬所有低优先级的CPU时间片
线程被永久堵塞在一个等待进入同步块的状态.(某方法加了锁,2个线程等待进入,其中1个进入之后事情处理不完出不来了,另1个线程就一直再等待,这也是饥饿问题)
等待的线程永远不被唤醒
如何尽量避免饥饿问题:
设置合理的优先级 ---- setPriority(),尽量解决
使用锁来代替 ---- synchronized
2.1.3 活锁
两个线程相互不停的谦让,然后又相互占用了.(2个人独木桥,相互让路例子)
2.2 性能问题
上下文切换(单cpu),时间片
2.3 线程安全性问题
-
- 多线程环境下
-
- 多个线程共享一个资源
-
- 对资源进行非原子性操作
满足以上三点就会有线程安全性问题
–整理于网络