并发编程

1.1

😭加油

2.1.进程和线程的区别

进程是操作系统分配资源的最小单位。

线程是依赖进程而存在的,线程是cpu调度的最小单位,也是进程的子集,是一段计算逻辑的cpu调度载体。

进程之间可以通过磁盘,网络进行通信,而同一个进程的资源都是共享的,所以线程之间可以直接通过内存来进行通信。

2.2.上下文切换

在实际应用中,cpu物理核数N是固定的,有时候看到的表象是有N+个线程在同时执行,是操作系统分配cpu执行时间片造成的假象。

线程1切换到线程2这个过程叫上下文切换。从线程1切换到线程2的时候,对于线程1要做的事情是保存现场(寄存器负责保存当前线程下的正在使用的数据,程序计数器负责记录指令已执行的行号),对于线程2要做得事情就是还原现场(通过寄存器和程序计数器来还原数据和当前要执行的指令)。

 2.3.并行和并发

并行是同一时刻执行多个任务,但是多个任务都有独立的资源支撑。

并发是同一时刻执行多个任务,但是多个任务共享依赖同一个资源。

最终来看,并行是同时执行,并发是交替执行。

3.1.Java线程的创建和启动

main方法本身也是线程。


import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class OnlyMain {

public static void main(String[] args) {
// Java虚拟线程的管理接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要获取同步monitor和synchronized信息,仅获取线程和线程堆栈信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("["+threadInfo.getThreadId()+"] ["+threadInfo.getThreadName()+"]");
}
}
}

[5] [Monitor Ctrl-Break]    监控Ctrl-Break中断信号的
[4] [Signal Dispatcher]     分发处理发送给JVM信号的线程
[3] [Finalizer]             调用对象finalize方法的线程
[2] [Reference Handler]     清除Reference的线程
[1] [main]              main线程,用户程序入口            

 

 创建线程方式

1:使用或者继承Thread类

public static void main(String[] args) {
  Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName() + ":运行线程"), "t1");
  thread.start();
}

2.实现Runnable接口配合Thread类

public static void main(String[] args) {
  Runnable runnable = () -> {
    System.out.println(Thread.currentThread().getName() + ":运行线程");
  };
  Thread thread = new Thread(runnable,"t2");
  thread.start();
}

3.实现Callable接口配合FutureTask类和Thread类,这种方式可以获取线程中的返回值和异常

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> callable = () -> {
            System.out.println(Thread.currentThread().getName() + ":运行线程");
            return "success";
        };
        FutureTask<String> futureTask = new FutureTask<>(callable);
        Thread thread = new Thread(futureTask, "t3");
        thread.start();
        String state = futureTask.get();
        System.out.println("返回状态:" + state);
    }

3.2.Java线程的生命周期

线程在操作系统层面有5种状态,在Java层面有6种状态。

操作系统:

  新建:仅是在语言层面创建了线程对象,还未与操作系统线程关联。

  就绪:该线程已与操作系统线程完成了关联,可以由CPU调度执行了。

  运行:获取了CPU时间片运行中的状态,当CPU时间片用完,会从【运行状态】转换至【就绪状态】,会导致线程的上下文切换。

  阻塞:如果在线程执行中发生了IO,会从【运行状态】转换至【阻塞状态】,会导致线程的上下文切换,等IO完成之后会由操作系统唤醒阻塞的线程切换至【就绪状态】,只要阻塞状态的线程一直不被唤醒,就一直不会被调度执行。

  死亡:表示线程已经执行完毕,生命周期已经结束,不会再切换状态。

Java层面:

  初始(NEW):新创建了一个线程对象,但还没有调用start()方法。

  运行(RUNNABLE):Java线程将就绪(ready)和运行中(running)统称为运行状态,线程在等待CPU时间片分配的过程被称为ready,线程在获取CPU时间片执行的过程被称为running。

  阻塞(BLOCKED):线程在等待获取锁的过程叫阻塞状态。

  等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

  超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。

  终止(TERMINATED):表示线程执行完毕。

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

 3.3.sleep方法

调用之后会将线程状态从RUNNABLE转换成TIMED_WAITING,并且不会释放对象锁,其他现场调用interrupt方法可以中断睡眠并抛出异常。

public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("执行完成");
},"t1");
t1.start();
log.info("线程t1的执行状态:"+t1.getState());

try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

log.info("线程t1的执行状态:"+t1.getState());

t1.interrupt();

}

3.4.线程的优先级

在Java中是可以给线程设置优先级的,优先级范围是1~10,默认优先级一般都是5,调度器一般会忽略优先级,众生平等。

public static void main(String[] args) {
        Runnable r1 = () -> {
            int count = 0;
            for (; ; ) {
                log.info("r1 -> {}", count);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Runnable r2 = () -> {
            int count = 0;
            for (; ; ) {
                log.info("r2 -> {}", count);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t1 = new Thread(r1,"t1");
        t1.setPriority(Thread.MIN_PRIORITY);
        Thread t2 = new Thread(r2,"t2");
        t2.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();

    }

3.5.join方法

调用子线程的join方法之后主线程会进行阻塞,直到子线程执行完成之后,主线程才会继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。

public static int count = 0;

    public static void main(String[] args) {
        log.info("开始执行");
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(3000);
                count++;
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("最终结果:{}",count);
    }
看执行时间相差六秒
22:05:10.246 [main] INFO com.data.source.service.impl.UserServiceImpl - 开始执行
22:05:16.291 [main] INFO com.data.source.service.impl.UserServiceImpl - 最终结果:1

Process finished with exit code 0

3.6.守护线程

主死从随,主线程是主守护现场是从,类似golang的线程和协程的关系

守护线程常用的场景:

jvm垃圾回收线程,当用户线程结束不再产生垃圾,守护线程自然会结束。

中间件的心跳检测,事件监听,当任务终止之后,守护线程自然会结束。

public static void main(String[] args) {
        log.info("主线程开始执行");
        Thread t1 = new Thread(()->{
            try {
                log.info("子线程开始执行");
                Thread.sleep(3000);
                log.info("子线程执行结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.setDaemon(true);
        t1.start();
        log.info("主线程执行结束");
    }

22:12:42.917 [main] INFO com.data.source.service.impl.UserServiceImpl - 主线程开始执行
22:12:42.950 [main] INFO com.data.source.service.impl.UserServiceImpl - 主线程执行结束
22:12:42.950 [Thread-0] INFO com.data.source.service.impl.UserServiceImpl - 子线程开始执行

 3.7.利用中断机制正确终止线程

t1线程正常中断,中断状态不会被重置

public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                Thread currentThread = Thread.currentThread();
                boolean interrupted = currentThread.isInterrupted();
                if (interrupted) {
                    break;
                }
                log.info("任务执行完成..");
            }
        });
        t1.start();
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t1.interrupt();
        log.info("t1线程的中断状态:{}", t1.isInterrupted());
    }

21:52:11.241 [Thread-0] INFO com.data.source.service.impl.UserServiceImpl - 任务执行完成..
21:52:11.242 [main] INFO com.data.source.service.impl.UserServiceImpl - t1线程的中断状态:true

 

如果线程出现了阻塞状态[Thread.sleep() Thread.join() 对象锁obj.wait()],使用中断之后会抛出中断异常并将中断标识位清除为flase

public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }

                log.info("任务执行完成..");
            }
        });
        t1.start();
        t1.interrupt();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("t1线程的中断状态:{}", t1.isInterrupted());
    }
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.data.source.service.impl.UserServiceImpl.lambda$main$1(UserServiceImpl.java:195)
    at java.lang.Thread.run(Thread.java:750)
22:02:57.694 [main] INFO com.data.source.service.impl.UserServiceImpl - t1线程的中断状态:false

public static void main(String[] args) {
Object o = new Object();
Thread t1 = new Thread(() -> {
while (true) {
synchronized (o){
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
break;
}

log.info("任务执行完成..");
}

}
});
t1.start();
t1.interrupt();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("t1线程的中断状态:{}", t1.isInterrupted());
}

java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.data.source.service.impl.UserServiceImpl.lambda$main$1(UserServiceImpl.java:197)
at java.lang.Thread.run(Thread.java:750)
22:10:29.412 [main] INFO com.data.source.service.impl.UserServiceImpl - t1线程的中断状态:false

 

posted @ 2024-07-09 20:56  我看见到处是阳光  阅读(1)  评论(0编辑  收藏  举报