-
运行中的应用程序叫进程,每个进程运行时,进程负责了内存空间的划分。它是系统进行资源分配和调度的一个独立单位。
-
*** 作系统都是支持多进程的
-
Windows是多任务的 *** 作系统,那么Windows是同时运行多个应用程序吗?
-
线程是轻重级的进程,是进程中一个负责程序执行的控制单元
-
线程是由进程创建的(寄生在进程中)
-
一个进程可以拥有多个线程,至少一个线程
-
线程有几种状态(新建new,就绪Runnable,运行Running,阻塞Blocked,死亡Dead)
-
开启多个线程是为了同时运行多部分代码,每个线程都 有自已的运行的内容,这个内容可以称线程要执行的任务。
-
打开360卫士,就是打开一个进程,一个进程里面有很多代码,这些代码就是谁来执行的呢?线程来执行这些代码。
1.2.2 多线程
-
多线程:在一个进程中有多个线程同时在执行不同的任务。
-
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务
-
如:百度网盘、腾讯会议。
-
同时执行多个任务的优势:减低CPU的闲置时间,从而提高CPU的利用率
-
当前 *** 作系统支持多线程
-
多线程最大的好处在于可以同时并发执行多个任务;
-
多线程可以最大限度地减低CPU的闲置时间,从而提高CPU的利用率
-
线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
-
多线程需要协调和管理,所以需要CPU时间跟踪线程;
-
线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
-
线程太多会导致控制太复杂,最终可能造成很多Bug
-
Java支持多线程
-
主线程的特殊之处在于:
-
任何一个Java程序启动时,一个线程立刻运行,它执行main方法,这个线程称为程序的主线程。
-
一个Java应用程序至少有两个线程,一个是主线程负责main方法代码执行;一个是垃圾回收器线程,负责了回收垃圾。
-
-
方式一:继承Thread类
-
方式二:实现Runnable接口
-
方式三:实现Callable接口
-
继承Java.lang.Thread类,并重写run() 方法。
案例1:打印输出0-100的数字,创建两个线程交替执行
package thread;
public class MyPrintThreadTest {
public static void main(String[] args) throws InterruptedException {
//创建2个线程对象
MyPeintTread thread1=new MyPeintTread("线程1");
MyPeintTread thread2=new MyPeintTread("线程2");
//start()方法
// 让 *** 作系统启动一个线程执行MyPrintThread对象run方法
// start方法调用之后,不会立即启动一个线程,线程的启动取决于 *** 作系统
thread1.start();
thread2.start();
//打印main方法执行完毕
System.out.println("main方法执行完毕");
}
}
package thread;
//打印1-100数字
public class MyPeintTread extends Thread {
//构造方法,传入线程名称
public MyPeintTread(String name) throws InterruptedException {
super(name);
}
// 重写run方法,线程会调用run方法
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//this.getName() 获取线程的名称
System.out.println(this.getName() + ":" + i);
}
}
}
案例2:模拟龟兔赛跑
package thread;
class MyThread3 extends Thread{
private int s=5;
@Override
public void run() {
while(true){
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
if (s<0){
System.out.println("乌龟跑完了");
break;
}
System.out.println("乌龟领先了,加油,还剩下"+s+"米");
s--;
}
}
}
package thread;
public class MyThread4 extends Thread{
private int s=5;
@Override
public void run() {
while(true){
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
if (s<0){
System.out.println("兔子跑完了");
break;
}
System.out.println("兔子领先了,加油,还剩下"+s+"米");
s--;
}
}
}
package thread;
public class RaceThreadTest {
public static void main(String[] args) {
MyThread3 myThread1=new MyThread3();
MyThread4 myThread2=new MyThread4();
myThread2.start();
myThread1.start();
}
}
案例1中的MyPrintThread要求继承ArrayList,如何创建多线程?继承Thread类就不能继承ArrayList,因为,java是单继承,所以就不合适了,也有的人认为让ArrayList继承Thread,MyPrintThread再继承ArrayList,或者Thread继承ArrayList,MyPrintThread再继承Thread,这两种方案都不可以,因为Thread和ArrayList是jdk提供的不能随便修改。
4.3 实现Runnable接口-
实现Java.lang.Runnable接口,并重写run() 方法;
注意:Runnable接口的存在主要是为了解决Java中不允许多继承的问题。
案例1:打印输出0-100的数字,创建两个线程交替执行package runnable;
import java.util.ArrayList;
//实现Runnable线程类
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
try {
//休眠500毫秒
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取执行run方法的当前线程的名称
String threadName = Thread.currentThread().getName();
System.out.println(threadName + ":" + i);
}
}
}
package runnable;
public class MyThreadTest {
public static void main(String[] args) {
//创建线程类
MyThread t1 = new MyThread();
//创建Thread对象包裹t1
Thread thread1 = new Thread(t1);
//启动线程
thread1.start();
//创建线程类
MyThread t2 = new MyThread();
//创建Thread对象包裹t1
Thread thread2 = new Thread(t2);
//启动线程
thread2.start();
}
}
案例2:模拟龟兔赛跑
package runnable;
//乌龟数线程
public class MyThread3 implements Runnable {
private int s = 5;
@Override
public void run() {
while (true) {
if (s < 0) {
System.out.println("乌龟跑完了");
break;
}
System.out.println("乌龟加油,还剩下" + s + "米");
s--;
}
}
}
package runnable;
//兔子线程
public class MyThread4 implements Runnable {
private int s = 5;
@Override
public void run() {
while (true) {
if (s < 0) {
System.out.println("兔子跑完了");
break;
}
System.out.println("兔子加油,还剩下" + s + "米");
s--;
}
}
}
package runnable;
public class RaceMyThreadTest {
public static void main(String[] args) {
//运行main方法线程主线程
//创建兔子线程类对象
MyThread4 myThread1 = new MyThread4();
//创建Thread对象
Thread t1 = new Thread(myThread1);
//启动线程
t1.start();
//创建乌龟线程类对象
MyThread3 myThread2 = new MyThread3();
//创建Thread对象
Thread t2 = new Thread(myThread2);
//启动线程
t2.start();
System.out.println("main方法完成");
}
}
案例1中MyThread如何实现返回值?
4.4 实现Callable接口-
使用Callable和Future创建线程
使用Callable创建线程和Runnable接口方式创建线程比较相似,不同的是,Callable接口提供了一个call() 方法作为线程执行体,而Runnable接口提供的是run()方法,同时,call()方法可以有返回值,而且需要用FutureTask类来包装Callable对象。
-
步骤:
1、定义实现Callable接口的类,实现call() 方法
2、创建Callable实现类实例,通过FutureTask类来包装Callable对象,该对象封装了Callable对象的call()方法的返回值。
3、将创建的FutureTask对象作为target参数传入,创建Thread线程实例并启动新线程。
4、调用FutureTask对象的get方法获取返回值。
package callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThreadTest {
public static void main(String[] args) throws ExecutionException,InterruptedException {
//创建CallableThread对象
CallableThread ct=new CallableThread();
//创建FutureTask对象,获取返回值
FutureTask task=new FutureTask<>(ct);
// 创建Tread对象
Thread t=new Thread(task);
t.start();
// FutureTask对象的get()方法获取CallableThread对象的call方法的返回值
//FutureTask的get方法会阻塞代码,等待t线程运行结束,获取返回值,才会往下运行
Integer sum=task.get();
System.out.println(sum);
}
}
package callable;
import java.util.concurrent.Callable;
public class CallableThread implements Callable {
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i <=100 ; i++) {
sum+=i;
}
return sum;
}
}
案例2:
package user;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package user;
import java.util.ArrayList;
import java.util.List;
public class UserService {
public List selectList(){
List users=new ArrayList<>();
User u1=new User("jack",20);
User u2=new User("jim",25);
users.add(u1);
users.add(u2);
return users;
}
}
package user;
import java.util.List;
import java.util.concurrent.Callable;
public class UserThread implements Callable> {
private UserService userService;
public UserThread(UserService userService) {
this.userService = userService;
}
@Override
public List call() throws Exception{
List users=userService.selectList();
return users;
}
}
package user;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class UserThreadTest {
public static void main(String[] args) {
//创建serService对象
UserService userService = new UserService();
//创建UserThread对象
UserThread userThread=new UserThread(userService);
//创建FutureFask对象
FutureTask> task=new FutureTask<>(userThread);
//创建Threa对象
Thread t=new Thread(task);
//启动线程
t.start();
//FutureTack对象get方法获取返回值
try {
List users=task.get();
System.out.println(users);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
4.5 创建线程的三种方式-比较
-
继承Thread类:
-
优势:Thread类已实现了Runnable接口,故使用更简单
-
劣势:无法继承其它父类
-
-
实现Runnable接口:
-
优势:可以继承其它类
-
劣势:编程方式稍微复杂,多写一行代码
-
-
实现Callable接口:
-
类似于Runnable,方法可以有返回值,并且可以抛出异常。但是Runnable不行。
-
-
Java中线程状态转换:
Java中线程存在以下几种状态 :
-
新线程:
-
新创建了一个线程对象,此时它仅仅作为一个对象实例存在, JVM没有为其分配CPU时间片和其他线程运行资源。
-
-
就绪状态:
-
在处于创建状态的线程中调用start方法将线程的状态转换为就绪状态。这时,线程已经得到除CPU时间之外的其它系统资源,只等JVM的线程调度器按照线程的优先级对该线程进行调度,从而使该线程拥有能够获得CPU时间片的机会
-
-
运行状态:
-
就绪态的线程获得cpu就进入运行态
-
-
等待/阻塞:
-
阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
-
-
死亡状态:
-
线程执行完它的任务时,由JVM收回线程占用的资源
-
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)