1.进程
在java中每运行一个程序就会产生一个进程,进程的名字就是程序名称。
如下编写一个名字叫做Hello的java程序,使用while循环使程序能够不断运行。
使用 javac 编译java程序
使用java 命令执行java程序
不关闭程序执行界面,再次打开一个命令行窗口使用jps命令查看正在运行的进程
2.线程
每一个进程都有一个主线程,代码就在线程中运行。
main方法就是在main线程中运行的
Thread.currentThread().getName()
Thread类中的currentThread()可以获取当前线程,getName()可以获取线程名称
创建线程
可以自定义一个类继承Thread类实现线程的创建,run()方法是线程逻辑代码执行的地方
class MyThread extends Thread{
// 使用ctrl+o选中需要重写的方法
@Override
public void run() {
// currentThread获取当前正在运行的线程
System.out.println(Thread.currentThread().getName());
}
}
在main方法中完成自定义类的实例化并且启动线程
MyThread thread=new MyThread();
thread.start();
3.线程的生命周期
可以参考文章
线程生命周期详解https://blog.csdn.net/houbin0912/article/details/77969563
4.线程执行方式
1.串行执行
把多个线程连接成串,然后按照顺序执行
join方法用于把线程连接成串,只有前面的进程执行完毕之后,下一个进程才能开始执行
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
// main方法运行在main线程中
MyThread t1=new MyThread();
MyThread2 t2=new MyThread2();
t1.start();
t1.join();
t2.start();
t2.join();
System.out.println("main方法执行完毕");
}
}
t1进程使用join方法必须要在t2进程启动之前使用,不然的话,可能并不会得出想要的进程执行顺序
如下程序虽然使用了 join方法但是如果多次运行,并不会进程并不会按照 t1->t2进程执行
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
// main方法运行在main线程中
MyThread t1=new MyThread();
MyThread2 t2=new MyThread2();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("main方法执行完毕");
}
}
2.并发执行
多个线程是独立的,谁先抢到cpu执行权,谁就能执行
package thread;
import static java.lang.Thread.currentThread;
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
// main方法运行在main线程中
System.out.println(Thread.currentThread().getName());
MyThread thread=new MyThread();
MyThread2 t2=new MyThread2();
thread.start();
t2.start();
// t2.join();
// thread.join();
}
}
//自定义线程类
class MyThread extends Thread{
// 使用ctrl+o选中需要重写的方法
@Override
public void run() {
// currentThread获取当前正在运行的线程
System.out.println("thread1:"+Thread.currentThread().getName());
}
}
class MyThread2 extends Thread{
// 使用ctrl+o选中需要重写的方法
@Override
public void run() {
// currentThread获取当前正在运行的线程
System.out.println("thread2:"+Thread.currentThread().getName());
}
}
多次运行之后会产生不一样的结果
5.线程休眠
使用静态方法sleep方法可以让线程等待特定时间,等时间过后再执行线程
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
// main方法运行在main线程中
MyThread t1=new MyThread();
MyThread2 t2=new MyThread2();
t1.start();
t2.start();
// main线程等待3s后再执行
Thread.sleep(3000);
System.out.println("main方法执行完毕");
}
}
//自定义线程类
class MyThread extends Thread{
// 使用ctrl+o选中需要重写的方法
@Override
public void run() {
// currentThread获取当前正在运行的线程
System.out.println("thread1:"+Thread.currentThread().getName());
}
}
class MyThread2 extends Thread{
// 使用ctrl+o选中需要重写的方法
@Override
public void run() {
// currentThread获取当前正在运行的线程
try {
// t2线程等待4秒之后再执行
MyThread2.sleep(4000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("thread2:"+Thread.currentThread().getName());
}
}
等待时间都是按照进程开始时间进行计算
执行顺序是 进程开始->线程t1->经过3s ->main线程 ->经过1s -> 线程t2 。
6.线程工作
创建线程对象时,可以只把逻辑传递给这个对象,不需要创建一个类继承Thread类,不必采用上面的低效方法。
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
// 传递逻辑时需要遵循规则 ()->{逻辑}
Thread t1=new Thread(()->{
System.out.println("线程t1执行");
});
t1.start();
System.out.println("线程main执行");
}
}
2.采用匿名内部类实现Runnable 接口的类的对象
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
// 传递逻辑实现匿名内部类 Runnable
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1执行");
}
});
t1.start();
System.out.println("线程main执行");
}
}
7.线程池
线程池就是线程对象的容器,可以根据需要,在启动时创建一个或者多个线程对象 。
1.创建固定个线程对象
ExecutorService executorService =Executors.newFixedThreadPool(3);
线程逻辑执行
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
如果线程池内的线程对象都被占用,再次提交线程,会进入阻塞状态,等待出现空闲的线程对象
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
// 创建固定数量的线程对象
ExecutorService executorService =Executors.newFixedThreadPool(3);
for(int i=0;i<5;i++){
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
}
}
2.根据需求动态创建线程
ExecutorService executorService1=Executors.newCachedThreadPool();
运行结果
3.单一线程
可以把某些工作,按照某一顺序执行可以使用单一线程
ExecutorService executorService1=Executors.newSingleThreadExecutor();
4.定时调度线程
ExecutorService executorService1=Executors.newScheduledThreadPool(3);
8.多线程同步
多线程同步的含义就是某一个资源在同一时间内只能被一个线程访问。
1.使用同步代码块防止出现错误
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
Mythread mythread=new Mythread();
new Thread(mythread,"线程1").start();
new Thread(mythread,"线程2").start();
new Thread(mythread,"线程3").start();
new Thread(mythread,"线程4").start();
}
}
class Mythread implements Runnable{
private int ticks=10;
Object lock= new Object();
@Override
public void run() {
// 设定同步代码块,lock可以是任意数据类型
synchronized (lock){
while(ticks>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"--"+"卖出的票"+ticks--);
}
}
}
}
2.使用同步方法
public class Java_Thread {
public static void main(String[] args) throws InterruptedException {
Mythread mythread=new Mythread();
new Thread(mythread,"线程1").start();
new Thread(mythread,"线程2").start();
new Thread(mythread,"线程3").start();
new Thread(mythread,"线程4").start();
}
}
class Mythread implements Runnable{
private int ticks=10;
Object lock= new Object();
@Override
public void run() {
while(true){
try {
sale();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(ticks<0){
break;
}
}
}
// 同步方法定义
private synchronized void sale() throws InterruptedException {
if(ticks>0){
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"--"+"卖出的票"+ticks--);
}
}
}