maven
<dependencies>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
dependencies>
logback.xml
<configuration >
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{HH:mm:ss} [%t] %logger - %m%npattern>
encoder>
appender>
<logger name="com.laowa" level="debug" additivity="false">
<appender-ref ref="STDOUT"/>
logger>
configuration>
@Slf4j
public class Demo1 {
public static void main(String[] args) {
// 通过匿名内部类创建一个线程并命名为t,重写它的run方法
Thread t = new Thread("t"){
@Override
public void run(){
log.debug("t is running");
}
};
t.start();
log.debug("main is running");
}
}

将线程(Thread)与可执行任务(Runnable)解耦,提高灵活性
@Slf4j
public class Demo2 {
public static void main(String[] args) {
// Runnable runnable = new Runnable() {
// @Override
// public void run() {
// log.debug("running");
// }
// };
// Thread t = new Thread(runnable,"t");
// 使用lambda表达式简化
Thread t = new Thread(()->{
log.debug("running");
},"t");
t.start();
log.debug("main is running");
}
}

FutureTask是Runnable子类(FutureRunnable)的子类可以接收Callable类型的参数,是对Runnable的扩展,可以用来获取任务的执行结果
@Slf4j
public class Demo3 {
static int a = 1;
static int b = 2;
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Callable也是函数式接口,可以用lambda表达式简化
FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.debug("thread running");
// 演示方便,此处应处理线程安全
return a+b;
}
});
Thread t = new Thread(task,"t");
t.start();
log.debug("结果:{}",task.get());
}
}

tasklist | findstr "8080"查看匹配字符串8080的进程taskkill /F /PID 10086杀死进程id为10086的进程Java方法的运行是基于JVM栈的,每个线程启动时,JVM就会给它分配一块栈内存
因为一些原因导致cpu不再执行当前线程没转而执行另一个线程,就会发生线程上下文切换
当发生上下文切换时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java中对应的概念就是程序计数器,它的作用时记住下一条jvm执行地址
start():
启动一个新线程,在新的线程运行run方法中的代码;start只是让线程进入就绪,里面代码不一定立刻运行(CPU的时间片还没有分到),每个线程的start只能调用一次,调用多次会抛出IllegalThreadStateException
run():
新的线程启动后会调用这个方法,如果在构造Thread对象传递了Runnable参数,则线程启动后会调用Runnable中的run方法,某人不执行任何操作,可以创建子类来覆盖默认行为
join()、join(long n)
父线程等待该线程运行结束,可以传入参数指定最多等待n毫秒
getId():
获取线程长整型的id,这个id是唯一的
getName()、setName(String name):
线程名的getter和setter方法,线程名会在日志中打印,可以清楚的分辨出不同的线程
getPriority()、setPriority(int newPriority):
线程优先级的getter和setter方法,Java中规定线程优先级是1~10的整数,较大的优先级能提高该线程被CPU调度的几率
getState():
获取线程状态,Java中线程的状态时用6个Enum表示,分别为NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
isInterrupted()、interruputed():
判断线程是否被打断,isInterruted非静态方法且不会清除打断标记,interrupted是静态方法且会清除打断标记
isAlive():
线程是否存活,即是否还没有运行完毕
interrupt():
打断线程,如果被打断的线程正在sleep、wait、join会导致被打断的线程抛出InterruptedException,并清除打断标记;如果正在运行的线程被打断,则会设置打断标记;park的线程被打断,也会设置打断标记
currentThread():
静态方法,获取当前执行该方法的线程
sleep(long millis):
TimeUnit.SECONDES.sleep(1)和Thread.sleep(1000)yield():
run方法仅仅是一个普通的方法调用,它并不启动一个线程,而且也可以随意调用;但start的方法会启动一个新的线程,它只能调用一次
@Slf4j
public class Demo4 {
public static void main(String[] args) {
Thread t = new Thread(()->{
log.debug("thread running");
},"t");
t.run();
t.start();
}
}

sleep后线程进入阻塞态,而yield后线程进入就绪态;sleep结束之前线程不会被分到时间片,而yield在没有其他线程用时间片时,他还是会分到时间片
join用作处理线程间的同步问题,当某个线程需要在另一个线程的处理结果基础上执行操作,就需要两个线程同步执行
同步的概念
@Slf4j
public class Demo {
static int num =0;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread("t"){
@Override
public void run(){
num++;
}
};
Thread t2 = new Thread(()->{
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
num*=10;
},"t2");
t.start();
t2.start();
t2.join();
log.debug("结果为{}",num);
}
}

这些方法已过时,容易破坏同步代码块,造成线程死锁
Java进程只有在所有线程结束之后才会结束,如果还有线程在运行,即使主线程结束,Java进程也不会结束,如以下代码
@Slf4j
public class Demo {
public static void main(String[] args){
Thread t = new Thread(()->{
while (true){
}
},"t");
t.start();
}
}
有一种特殊的线程叫守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束,通过setDaemon(true)来指定为守护线程


假设洗水壶1s,烧开水15s,洗茶杯1s,泡茶1s;对这些动作做一个规划
@Slf4j
public class Demo {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
washTeapot();
Thread t = new Thread(()->{
try {
heatUpWater();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t");
t.start();
washCup();
t.join();
makeTea();
long end = System.currentTimeMillis();
log.debug("用时{}s",(end-start)/1000);
}
private static void washTeapot() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
}
private static void heatUpWater() throws InterruptedException {
TimeUnit.SECONDS.sleep(15);
}
private static void washCup() throws InterruptedException{
TimeUnit.SECONDS.sleep(1);
}
private static void makeTea() throws InterruptedException{
TimeUnit.SECONDS.sleep(1);
}
}
