java 简单的进程代码_01 Java多线程编程的方法

01 Java多线程编程的方法

b90092c057972a03d4c6b76cc2ffa0f1.png2 进程与线程

2-1 应用

异步调用

多线程提供程序运行效率

2-2 思考

3 Java线程基本知识点

3-1 Java中线程的创建方法

方法1 (仅使用Thread类,重写run方法)

方法2(使用Thread配合Runable接口使用,推荐)

2种方法小结

方法3: FutureTask对象配合Thread对象使用(需要线程返回值)。

3-2 Java线程内部原理

基本概念:

Java中线程上下文切换(Thread Context Switch)

3-3 线程中常用方法

thread中部分方法:

interrput 与park结合使用

二阶段终止模式代码示例

守护线程(daemon)

3-4 线程的状态

从操作系统的角度

从Java程序的角度

3-5 多线程的简单实例-烧水泡茶

目录2 进程与线程异步调用

多线程提供程序运行效率

2-1 应用

2-2 思考

3 Java线程基本知识点从操作系统的角度

从Java程序的角度

thread中部分方法:

interrput 与park结合使用

二阶段终止模式代码示例

守护线程(daemon)

基本概念:

Java中线程上下文切换(Thread Context Switch)

方法1 (仅使用Thread类,重写run方法)

方法2(使用Thread配合Runable接口使用,推荐)

2种方法小结

方法3: FutureTask对象配合Thread对象使用(需要线程返回值)。

3-1 Java中线程的创建方法

3-2 Java线程内部原理

3-3 线程中常用方法

3-4 线程的状态

3-5 多线程的简单实例-烧水泡茶

主要参考资料

2 进程与线程

进程:可以视为程序的一个实例,有的程序可以开启多个实例,比如浏览器。有的只能一个实例,比如网易云音乐。

线程:进程包含多个线程,是一个指令流,是JAVA中最小的调度与资源分配单位,在windows中进程是不活动的,只是线程的容器。

从资源占用,与通信方法二个角度进行对比,对比进程之间,线程之间,进程与线程之间。

2-1 应用

异步调用

定义:从调用方式来说,调用分为同步调用与异步调用。区别在于是否让主程序等待。

多线程提供程序运行效率

2-2 思考

1.单核情况下,多线程的本质是让不同线程轮流占用cpu,避免一个线程总是占用CPU,其他程序无法干活。

2.多核情况下,多线程能够提高程序运行效率要具体情况具体分析,考虑2点:计算任务是否能够拆分(阿姆达尔定律)

3.IO操作不占用CPU,但是一般使用阻塞IO:即线程虽然不用CPU,但必须等待IO结束。阻塞IO没能充分利用CPU,所有需要有非阻塞IO和异步IO提高线程利用率。

3 Java线程基本知识点

3-1 Java中线程的创建方法

方法1 (仅使用Thread类,重写run方法)package chapter2;

//这个程序要运行必须在IDEA中装好lombok插件,并有lombok和slf4j-simple包

import lombok.extern.slf4j.Slf4j;    //导入注解

@Slf4j(topic = "c.Test1")

/*

new 类名或接口名(){

重写方法;

};     //注意分号

//以上就是内部类的格式,其实这整体就相当于是new出来的一个对象

本质:其实是继承该类或者实现接口的子类匿名对象

个人理解:一般我们实现接口或者继承某个对象的时候会另外在定义一个新的有名称的类。匿名内部类由于只使用

一次,就没必要特意的再去重新定义一下。

*/

/*方法1:直接使用Thread*/

public class Test1 {

public static  void main(String[] args){   //create the thread

Thread t = new Thread(){

public void run(){

log.warn("running");

}

};

t.setName("thread1");

t.start();                 // start the thread

log.warn("running");

}

}

方法2(使用Thread配合Runable接口使用,推荐)

目的:将运行的代码与线程的创建分开package chapter2;

//这个程序要运行必须在IDEA中装好lombok插件,并有lombok和slf4j-simple包

import lombok.extern.slf4j.Slf4j;    //导入注解

//方法2: Runable对象配合Thread对象使用

@Slf4j(topic = "c.Test2")

public class Test2 {

public static  void main(String[] args){   //create the thread

//        Runnable r = new Runnable() {    //定义匿名类实现Runable()接口

//            @Override

//            public void run() {

//                log.warn("running");

//            }

//        };

// annoyomous class create(lambda style)

// 定义匿名类实现Runable接口,并使用lamba方式简化

Runnable r = () -> log.warn("running");

new Thread(r, "thread1").start();

log.warn("running");

}

}

2种方法小结

方法1与方法2的联系:方法2中的Runable对象会作为参数传递给Thread的私有变量target,然后在run方法中被调用。本质上2种方法都是对线程对象中的run()方法进行修改。@Override

public void run() {

if (target != null) {

target.run();

}

}使用方法2方便与高级API线程池进行配合

使用方法2更加灵活,符合JAVA组合优于继承的思想。

可以使用jps查看所有进程,jstack PID查看该进程所有的线程

方法3: FutureTask对象配合Thread对象使用(需要线程返回值)。package chapter2;

//这个程序要运行必须在IDEA中装好lombok插件,并有lombok和slf4j-simple包

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.FutureTask;

//方法2: Runable对象配合Thread对象使用

@Slf4j(topic = "c.Test2")

public class Test3 {

public static  void main(String[] args) throws InterruptedException, ExecutionException {   //create the thread

// FutureTask对象能够返回进程的执行结果

// 源码中FutureTask对象实现了runable接口,因此可以传递给Thread对象

FutureTask task = new FutureTask(new Callable() {

@Override

public Integer call() throws Exception {

log.warn("Runing");

Thread.sleep(1000);

return 100;

}

});

Thread t = new Thread(task,"t1");

t.start();

log.warn("{}", task.get());

}

}

3-2 Java线程内部原理

基本概念:

栈与栈帧:线程执行后,被分配一个栈内存。线程之间的栈内存互不干扰。栈帧(frames):每个栈内存有许多栈帧组成,一个栈帧对应一次方法调用(利用栈的特性先进后出实现多次方法调用)

活动栈帧:每个线程当前只有一个活动栈帧,即当前线程执行的方法

0ab6adb9377945319346541afe549192.png

Java中线程上下文切换(Thread Context Switch)

何时发生?垃圾回收

时间片用完

更高优先级线程

线程主动sleep,yield,wait,join,park,synchronized,lock

3-3 线程中常用方法

thread中部分方法:方法名start()|run()创建线程并让线程处于就绪态(runable)|执行线程代码,不会创建线程

sleep()让线程由 running 变为 Time waiting(一定时间内无法被调度)

yield() 屈服,让步; 放弃; 让路;让线程由 running 变为 runable(仍然可被调度)

join()等待线程运行结束(线程同步,需要运行的结果)

interrupt()打断线程(包括阻塞的与正在运行的)

下面3个方法是过时方法容易破坏同步代码块,造成死锁。

stop()使用2阶段终止模式进行替代

suspend()

resume()

sleep():可以配合interrupt使用,interrupt可以wake up线程

yield():放弃CPU的使用权,依赖于CPU的调度器,会出现线程yield之后,任务调度器仍然调度该线程的情况。

interrupt():中断线程的阻塞状态(采用sleep(),join(),wait()方法后的线程)

中断正常的线程,会使得线程中断标记为True结合中断标记去优雅的停止线程package chapter2;

//这个程序要运行必须在IDEA中装好lombok插件,并有lombok和slf4j-simple包

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.FutureTask;

//方法2: Runable对象配合Thread对象使用

@Slf4j(topic = "c.Test2")

public class Test4 {

public static  void main(String[] args) throws InterruptedException, ExecutionException {   //create the thread

Thread t1 = new Thread(() -> {

while(true){

if(Thread.currentThread().isInterrupted()){  //当前线程是否被中断过

//                    System.out.println("break the loop");

log.warn("break the loop");

break;

}

}

},"t1");

t1.start();

Thread.sleep(1000);  // main线程休眠1s

log.warn("interrupt t1");

t1.interrupt();            // 中断线程t1

}

}

运行结果:[main] WARN c.Test2 - interrupt t1

[t1] WARN c.Test2 - break the loop

Process finished with exit code 0

interrput 与park结合使用package chapter2;

//这个程序要运行必须在IDEA中装好lombok插件,并有lombok和slf4j-simple包

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.locks.LockSupport;

//方法2: Runable对象配合Thread对象使用

@Slf4j(topic = "c.Test7")

public class Test7 {

public static  void main(String[] args) throws InterruptedException{   //create the thread

log.warn("the main thread!");

parktest();

}

// park处于调度的考虑让当前线程不执行,等待获取许可证,除非被当前线程unpark方法调用。

private static void parktest() throws InterruptedException{

Runnable r = ()->{

// 定义匿名类实现Runable接口,由于Runable是函数式接口,因此可以通过lamba进行简化

log.warn("park...");

LockSupport.park();

log.warn("unpark...");

// interrupted()    方法会查看中断状态,将中断标记重置为假。

// isinterrupted()  方法仅查看中断状态

// park之后,用interrupt恢复后,必须恢复中断标记为假,否则再次park会失效。

log.debug("interrupt state: {}", Thread.interrupted());

};

Thread t1 = new Thread(r,"t1");

t1.start();

t1.sleep(1000);

t1.interrupt();      // 通过interrupt可以恢复park的进程,并将中断标志变为True

}

}

执行结果:[main] WARN c.Test7 - the main thread!

[t1] WARN c.Test7 - park...

[t1] WARN c.Test7 - unpark...

注意点:park方法能够让线程停止运行

park之后,可以用interrupt恢复运行,但必须手动恢复中断标记为假,否则再次park会失效。

区分2个方法interrupt以及isinterrupted

二阶段终止模式代码示例

103ab1b0fe635c73ed855c95fc01dd44.pngpackage chapter2;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;

@Slf4j(topic = "c.Test6")

public class Test6 {

public static  void main(String[] args) throws InterruptedException, ExecutionException {

TwoStageTermination tmp = new TwoStageTermination();

tmp.start();

Thread.sleep(5000);

tmp.stop();

}

}

/*

* 每隔2s运行并检查,可通过外部线程杀死该线程

* */

@Slf4j(topic = "c.TwoStageTermination")

class TwoStageTermination

{

private Thread monitor;

public void stop(){       /* 正常状态停止(中断)监控进程*/

monitor.interrupt();    /* 设置中断标记为true*/

}

public void start(){

monitor = new Thread(() -> {

while(true){

Thread current = Thread.currentThread();

if(current.isInterrupted()){

log.warn("stop the thread of monitor!");

break;

}

try{

current.sleep(2000);

log.warn("sleep 2 seconds !");

log.warn("check the status...");

}catch(Exception e){

e.printStackTrace();

current.interrupt();    /* 设置中断标记为true*/

}

}

},"monitor_thread");

monitor.start();

}

}

运行结果:[monitor_thread] WARN c.TwoStageTermination - sleep 2 seconds !

[monitor_thread] WARN c.TwoStageTermination - check the status...

[monitor_thread] WARN c.TwoStageTermination - sleep 2 seconds !

[monitor_thread] WARN c.TwoStageTermination - check the status...

java.lang.InterruptedException: sleep interrupted

at java.lang.Thread.sleep(Native Method)

at chapter2.TwoStageTermination.lambda$start$0(Test6.java:36)

at java.lang.Thread.run(Thread.java:748)

[monitor_thread] WARN c.TwoStageTermination - stop the thread of monitor!注意点:线程在sleep状态被interrupt会触发异常,中断标记为false

线程运行状态被interrupt,中断标记为true。

二阶段终止模式可以用于过时的stop方法

守护线程(daemon)

知识点:通常Java进程会在主线程以及其他线程运行结束后才会结束。

但对于守护线程而言,进程结束无需考虑守护线程是否已经停止。

守护进程的实际例子:Java中的垃圾回收线程

Tomcat中的Acceptor以及Poller线程都是守护线程

3-4 线程的状态

从操作系统的角度

可以划分为:开始,可执行(就绪),执行,阻塞,结束

从Java程序的角度

在Java的源代码Thread.java文件中定义了6种状态,分别是

NEW:线程刚刚被创建时,还没有start()的状态

RUNABLE: Java中的RUNABLE包含了操作系统层面的运行,阻塞,可运行状态。

BLOCKED,WAITING,TIMED_WAITINGJava API层面的阻塞TIMED_WAITING:使用sleep方法可能会出现

WAITING:  使用join方法后可能会出现

BLOCKED:使用synchronize方法可能会出现

TERMINATED:程序终止状态

ad1cab919b70d51f75774f3e60f3bf50.pngpublic 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:

*   

{@link Object#wait() Object.wait} with no timeout

*   

{@link #join() Thread.join} with no timeout

*   

{@link LockSupport#park() LockSupport.park}

*

A thread in the waiting state is waiting for another thread to

* perform a particular action.

*

* For example, a thread that has called Object.wait()

* on an object is waiting for another thread to call

Object.notify() or Object.notifyAll() on

* that object. A thread that has called Thread.join()

* 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:

*   

{@link #sleep Thread.sleep}

*   

{@link Object#wait(long) Object.wait} with timeout

*   

{@link #join(long) Thread.join} with timeout

*   

{@link LockSupport#parkNanos LockSupport.parkNanos}

*   

{@link LockSupport#parkUntil LockSupport.parkUntil}

*/

TIMED_WAITING,

/**

* Thread state for a terminated thread.

* The thread has completed execution.

*/

TERMINATED;

}

3-5 多线程的简单实例-烧水泡茶

场景:

c221233bd0597556da034d6d2e3e9495.png

封装好的Sleeper类package chapter2;

import java.util.concurrent.TimeUnit;

public class Sleeper {

public static void sleep(int i){

try{

TimeUnit.SECONDS.sleep(i);

}catch (InterruptedException e){

e.printStackTrace();

}

}

}

主程序package chapter2;

//这个程序要运行必须在IDEA中装好lombok插件,并有lombok和slf4j-simple包

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

//方法2: Runable对象配合Thread对象使用

@Slf4j(topic = "c.Test8")

public class Test8 {

public static  void main(String[] args){   //create the thread

Thread t1 = new Thread(()->{

log.warn("洗水壶");

Sleeper.sleep(1);

log.warn("烧开水");

Sleeper.sleep(15);

log.warn("完成洗茶壶和烧开水");

},"老王");

Thread t2 = new Thread(()->{

log.warn("洗茶壶");

Sleeper.sleep(1);

log.warn("洗茶杯");

Sleeper.sleep(2);

log.warn("拿茶叶");

Sleeper.sleep(1);

log.warn("完成洗茶壶和茶杯,拿茶叶");

try{

t1.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

log.warn("小王泡茶");

},"小王");

t1.start();

t2.start();

}

}

执行结果:[小王] WARN c.Test8 - 洗茶壶

[老王] WARN c.Test8 - 洗水壶

[老王] WARN c.Test8 - 烧开水

[小王] WARN c.Test8 - 洗茶杯

[小王] WARN c.Test8 - 拿茶叶

[小王] WARN c.Test8 - 完成洗茶壶和茶杯,拿茶叶

[老王] WARN c.Test8 - 完成洗茶壶和烧开水

[小王] WARN c.Test8 - 小王泡茶

总结: 使用2个线程进行了统筹规划,利用join完成最后的同步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于Java设计解决多线程编程进程间同步和互斥问题的示例代码。 1. 进程间同步问题的解决 在Java中,我们可以使用synchronized关键字来实现进程间同步。 ```java public class SyncExample { private int count = 0; public synchronized void add() { for (int i = 0; i < 1000000; i++) { count++; } } public static void main(String[] args) throws InterruptedException { SyncExample syncExample = new SyncExample(); Thread t1 = new Thread(() -> syncExample.add()); Thread t2 = new Thread(() -> syncExample.add()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(syncExample.count); } } ``` 在上面的代码中,我们定义了一个SyncExample类,其中包含了一个count变量和一个add()方法。在add()方法中,我们使用synchronized关键字来保证在任何时刻只有一个线程可以执行该方法。在main()方法中,我们创建了两个线程并启动它们,然后等待它们执行完毕并输出结果。 2. 进程间互斥问题的解决 在Java中,我们可以使用Lock和Condition接口来实现进程间互斥。 ```java import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockExample { private int count = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private boolean flag = false; public void add() throws InterruptedException { lock.lock(); try { while (flag) { condition.await(); } for (int i = 0; i < 1000000; i++) { count++; } flag = true; condition.signal(); } finally { lock.unlock(); } } public static void main(String[] args) throws InterruptedException { LockExample lockExample = new LockExample(); Thread t1 = new Thread(() -> { try { lockExample.add(); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread t2 = new Thread(() -> { try { lockExample.add(); } catch (InterruptedException e) { e.printStackTrace(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(lockExample.count); } } ``` 在上面的代码中,我们定义了一个LockExample类,其中包含了一个count变量和一个add()方法。在add()方法中,我们首先获取锁,然后使用while循环来判断是否满足某个条件,如果不满足则调用condition.await()方法等待其他线程的通知。当满足条件时,我们对count变量进行1000000次加1操作,然后将flag标记为true并调用condition.signal()方法通知其他线程条件已经满足。在main()方法中,我们创建了两个线程并启动它们,然后等待它们执行完毕并输出结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值