多线程介绍:
多线程是java中的一个并发的概念:
在计算机的运行中,所有的进程都是同时运行的(cpu会同时调用,之后随机的获取分配)
1.在java程序中也是支持的!
2.在java执行main方法的时候,其实就是执行一个名字叫做main的线程,可以在main线程执行的时候,开启多个其他的线程A,B,C等等,多个线程A,B,C等等都是同时执行的,同时等等cpu的调用,相互抢夺cpu调用自己的时间片段。
3.Thread类是java中的专门用于处理线程的api,是java.lang下的常用类,每一个Thread类的对象,
就代表一个某种状态的线程。
java.lang包下的常用的类有:String,System,八大基本类型,Thread…
进程:表示一个个的正在运行的程序,比如qq,qq音乐,网易云…
- 线程:表示一个个正在运行程序中的子进程(线程),qq的聊天窗口
- 包含关系:一个进程包含多个进程
- java中的线程是支持多线程的,多个线程可以同时进行,但是不能保证(控制)线程的运行,具体是看CPU的调用,我们只能看到结果。
java中使用Thread类来创建线程
第一种方式:
步骤:
- 1.指定执行线程的目标:定义一个Thread子类,重写run方法,将相关的逻辑实现,public void run():将需要的逻辑写在里面,该方法相当于线程中的main方法。
- 2.创建自定义线程的子类对象
3.开启线程操作 - 触发
public void start():只要调用了这个方法,线程才会启动,开始执行
Thread中的相关方法:
- public final String getName():获取线程的名称
- public final void setName():设置线程的名字
- public static Thread currentThread():获取当前的线程对象
线程的运行默认是不可控制的,是cpu随机调用,我们只能看到运行的结果。
**
package ThreadDemo1;
/**
* 自定义线程类
* 定义一个Thread的子类!
*
* 创建线程的第一种方式:继承Thread类
*/
public class MyThread extends Thread{
//重写run方法 - 相关的逻辑写进去
@Override
public void run(){
for (int i = 0; i < 50; i++) {
/*
this表示当前正在被调用的这个线程
获取线程的名字是java干的事情(java定义的),我们不管,只要看就行了
*/
System.out.println(this.getName()+":"+i);
}
}
}
package ThreadDemo1;
public class ThreadDemo1 {
//主线程
public static void main(String[] args) {
//创建线程对象 - 用于开启线程
Thread t0 = new MyThread();
Thread t1 = new MyThread();
//开启线程 - 直接运行
t0.start();
t1.start();
System.out.println("===========================");
//返回一个main线程 - 其实就是main方法的线程
Thread mainThread = Thread.currentThread();
System.out.println(mainThread);//Thread[main,5,main]
for (int i = 0; i < 50; i++) {
System.out.println(mainThread.getName()+":"+i);
}
}
}
start()方法的作用1.启动当前线程2.调用当前线程的run()
第二种方式:实现Runnable接口
- 1.实现接口,并且要实现run方法
- 2.在run方法中添加逻辑代码
- 3.通过start启动线程
- ```java package ThreadDemo1;
/**
创建线程的第二种方式: */ public class MyRunnable implements Runnable{
@Override public void run() {
//返回当前线程
Thread thisThread = Thread.currentThread();
} }
**步骤:**
- 1.指定线程执行的目标:定义Runnable接口,并且实现接口,重写run方法,指定目标逻辑
- 2.通过指定线程执行目标的构造方法创建线程对象
- public Thread(Runnable target)
- 1)创建线程,并且执行目标对象
- 2)通过线程执行目标对象创建线程对象
- 3.开启线程操作(start)
**好处:将任务和线程相分离,耦合度比较低,使用也更加的广泛。**
```java
package ThreadDemo1;
/**
* java中使用Thread类来创建线程:语法
*第二种方式:
*
*/
public class ThreadDemo2 {
//主线程
public static void main(String[] args) {
//创建线程执行目标
MyRunnable mr = new MyRunnable();//线程对象 - 任务
//通过指定线程执行目标的构造函数来创建线程
Thread thread = new Thread(mr);//线程名称
thread.setName("jack");
Thread thread2 = new Thread(mr);//线程名称
thread.setName("rose");
//开启线程
thread.start();
thread2.start();
}
}
线程的优先级
说明:高优先级的线程要抢占低优先级线程的CPU执行权。但是只是 从概率上讲,高优先级的线程高概率
会被执行,并不意味着只有高优先级执行完后,低优先级才会执行。
**
匿名内部类创建线程 - 实际开发中使用
- 1.使用匿名内部类创建线程的原理和普通类创建线程原理完全一样。
- 2.区别在于利用匿名内部类创建线程的写法更加的简洁,使用非常多。 ```java package AnonysThread;
/**
- 匿名内部类创建线程 - 实际开发中使用 *
- 1.使用匿名内部类创建线程的原理和普通类创建线程原理完全一样。
2.区别在于利用匿名内部类创建线程的写法更加的简洁,使用非常多。 / public class AnonysThreadDemo { public static void main(String[] args) {
//方式一:使用匿名内部类创建线程的子类对象
Thread t1 = new Thread(){
@Override
public void run(){
System.out.println("我很好");
}
};
t1.start();
System.out.println("-----------------------------------------------");
//使用匿名内部类,创建线程的匿名子类对象,并且启动线程
new Thread(){
@Override
public void run(){
System.out.println("还记得上次你我身旁的样子");
}
}.start();
//方式二:使用匿名内部类的方式,创建执行目标类的对象
Runnable r = new Runnable(){
@Override
public void run(){
System.out.println("她来了然后他死了");
}
};
//传入到构造函数
Thread t2 = new Thread(r);
t2.start();
System.out.println("==========================================");
//组合写法 - 精简写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("往事只能后悔");
}
}).start();
//t3的普通写法
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("往事只能后悔");
}
});
t3.start();
} }
**线程的生命周期**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608015124063-999f19e7-e55f-4599-8452-cddb99ca800c.png#align=left&display=inline&height=255&margin=%5Bobject%20Object%5D&name=image.png&originHeight=510&originWidth=1194&size=248306&status=done&style=none&width=597)**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608039058241-07d5c2db-24ef-42cf-a39d-68afbe0c99fa.png#align=left&display=inline&height=218&margin=%5Bobject%20Object%5D&name=image.png&originHeight=435&originWidth=829&size=290722&status=done&style=none&width=414.5)**<br />**![](https://cdn.nlark.com/yuque/0/2020/png/2875088/1607995515730-951ca6d8-d924-4b09-bb0a-defab47232d8.png#align=left&display=inline&height=448&margin=%5Bobject%20Object%5D&originHeight=448&originWidth=828&status=done&style=none&width=828)<br />**线程的安全问题**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608040597262-7a557bba-5f93-47e1-8689-76a65f9e7034.png#align=left&display=inline&height=300&margin=%5Bobject%20Object%5D&name=image.png&originHeight=599&originWidth=999&size=272694&status=done&style=none&width=499.5)**<br />**在java中我们通过同步机制来解决线程的安全问题**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608041327859-e663d436-5eab-4d3c-b64b-f812f0d2f72b.png#align=left&display=inline&height=118&margin=%5Bobject%20Object%5D&name=image.png&originHeight=235&originWidth=712&size=155899&status=done&style=none&width=356)**<br />**要求:多个线程必须共用一把锁**<br />**同步方法**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608079587860-1b998fbf-738e-44c3-8d20-709cb1cada34.png#align=left&display=inline&height=90&margin=%5Bobject%20Object%5D&name=image.png&originHeight=179&originWidth=621&size=149124&status=done&style=none&width=310.5)**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608080422308-f1a740bd-0e86-4b78-bde9-fb3f6b0c6bbe.png#align=left&display=inline&height=40&margin=%5Bobject%20Object%5D&name=image.png&originHeight=80&originWidth=935&size=132311&status=done&style=none&width=467.5)**<br />** 说明:这三个方法只能出现在同步代码块和同步方法中**<br />**这三个方法的调用者必须是同步代码快或同步方法中的同步监视器**<br /> 实现callable接口创建线程
```java
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 创建线程的方式三:实现callable接口。------jdk5.0新增
*/
//创建一个实现callable接口的实现类
class CallableTest implements Callable {
//实习call方法,将此线程需要执行的操作声明在call()方法中
@Override
public Object call() throws Exception {
int sum=0;
for (int i = 0; i <= 100; i++) {
if(i%2==0){
System.out.println(i);
sum+=i;
}
}
return sum;
}
}
public class ThreadNew{
public static void main(String[] args) throws ExecutionException {
//创建callable接口实现类对象
CallableTest callableTest = new CallableTest();
//将次callable接口实现类对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
FutureTask futureTask = new FutureTask(callableTest);
//将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
new Thread(futureTask).start();
try {
//获取callable中call方法的返回值
//get()方法的返回值即为FutureTask构造器参数callcable实现类重写call()的返回值
Object sum = futureTask.get();
System.out.println("总和是" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用线程池创建线程
Executors:工具类,线程池工厂类,用于创建并返回不同类型的线程池
ExecutorService:真正的线程池接口
class NumberThread implements Runnable{
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
class NumberThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
public class ThreadPoolTest {
public static void main(String[] args) {
//提供指定线程数量的连接池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//设置线程池属性
System.out.println(executorService.getClass());
//执行指定线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
executorService.execute(new NumberThread());//适合适用于Runnable
executorService.execute(new NumberThread1());
//executorService.submit();//适合使用于Callablle
executorService.shutdown();//关闭连接池
}
}
**