本文目录
1.多线程
1.1线程和进程
进程:计算机正在运行的一个独立的应用程序
线程:是组成进程的基本单位
一个进程由一个或多个线程组成
进程是独享内存空间,线程是共享内存空间(线程执行是相互独立的)
单独的线程无法执行,必须依赖于进程才能执行
多线程:在一个进程中,多个线程同时执行,其实是所有线程轮流交替占用CPU资源,中间过程较短,所以说多个线程同时执行
main方法就是一个单线程,所以先输出循环Test,再输出循环Test2
线程是用来执行任务的,每个线程对象都需要绑定一个任务
Java 中线程是对象,任务也是对象
1.2Java中线程的使用
继承Thread类 ,实现Runnable接口
1.继承Thread类
两个线程交替占用cpu运行
继承Thread类将任务和线程绑定了,这个线程就只能做这种事,解耦合度高
2.实现Runnable接口
Runnable 接口就是用来描述任务的,实现 run 方法来描述任务
实现线程和任务的解耦合,单独定义一个类实现 Runnable接口作为任务,创建 Thread 对象之后再把任务整合进去
定义任务
package test;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("===Runnable===");
}
}
}
创造线程,执行任务
package test;
public class Test {
public static void main(String[] args) {
//创建任务
MyRunnable myRunnable = new MyRunnable();
//创建线程
Thread thread = new Thread(myRunnable);
thread.start();
}
}
1.3线程的状态
- 创建状态 相当于(Thread thread = new Thread(myRunnable);)
- 就绪状态 相当于(thread.start();)
- 运行状态 (交替执行时 ,正在执行的线程就属于运行状态)
- 阻塞状态 (交替执行时 ,其他线程占用cpu执行时,此时此线程属于阻塞状态)
- 终止状态
1.4线程调度
1.线程休眠
让当前线程暂停执行,运行状态->阻塞状态,让出 CPU 资源,sleep(long millis) 单位毫秒,创建出的线程都可以调用sleep,主线程不行
package test;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i==5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("---MyThread---");
}
}
}
//外部做休眠
package test;
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
try {
myThread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myThread.start();
for (int i = 0; i < 100; i++) {
System.out.println("---main---");
}
}
}
主线程调用sleep方法 Thread.currentThread().sleep(1000);
package test;
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
if(i==5){
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
System.out.println("---main---");
}
}
}
2.线程合并
将指定的某个线程加入到当前线程中,合并为一个线程。join()
A 和 B,B.join() 表示当前开始 CPU 资源被 B 独占,A 进入阻塞状态,B 执行完毕,A 才能继续继续执行。
package test;
public class JoinRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i + "------JoinRunnable");
}
}
}
package test;
public class Test {
public static void main(String[] args) {
JoinRunnable joinRunnable = new JoinRunnable();
Thread thread = new Thread(joinRunnable);
thread.start();
for (int i = 0; i < 100; i++) {
if(i == 10){
try {
thread.join();
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
System.out.println(i + "======main");
}
}
}
当运行到9时,从10开始都是执行joinRunnable,知道joinRunnable执行完成
join有个方法重写
join(long millis)
B.join() 表示当前开始 CPU 资源被 B 独占,A 进入阻塞状态,在 millis 时间内 B 独占 CPU 资源进行执行,但是时间一到无论 B 是否执行完毕,都会释放 CPU 资源,和 A 继续交替执行。
package test;
public class JoinRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i + "------ JoinRunnable");
}
}
}
package test;
public class Test {
public static void main(String[] args) {
JoinRunnable joinRunnable = new JoinRunnable();
Thread thread = new Thread(joinRunnable);
thread.start();
for (int i = 0; i < 100; i++) {
if(i == 10){
try {
thread.join(3000);
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
System.out.println(i + "======main");
}
}
}
3.线程礼让
在某个特定的时间点,让线程暂停抢占 CPU 资源的行为,运行状态 -> 阻塞状态,yield(),当这个礼让之后继续抢占资源
线程1
package test;
public class YieldThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if(i==5){
Thread.currentThread().yield();
}
System.out.println(Thread.currentThread().getN
ame() + "------" + i);
}
}
}
线程2
package test;
public class YieldThread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "------" + i);
}
}
}
运行
package test;
public class Test {
public static void main(String[] args) {
YieldThread1 thread1 = new YieldThread1();
thread1.setName("线程A");
YieldThread2 thread2 = new YieldThread2();
thread2.setName("线程B");
thread1.start();
thread2.start();
}
}
结果,在id=5 ,A礼让了B
1.5线程同步
多个线程同时访问某个资源时,不是同时对资源进行访问修改,而是顺序执行。
多个线程同时访问共享资源时,可能会存在数据错误的情况,如何解决?
通过线程同步,多个线程不是同时访问数据,而是顺序访问。
1.synchronized 修饰实例方法
//当上一个线程走完时,才会走下一个线程
package test;
public class Account implements Runnable {
private static int num;
@Override
public synchronized void run() {
try {
Thread.currentThread().sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
num++;
System.out.println(Thread.currentThread().getN
ame() + "是当前的第" + num + "位访客");
}
}
package test;
public class Test {
public static void main(String[] args) {
Account account = new Account();
Thread thread1 = new Thread(account,"线 程A");
Thread thread2 = new Thread(account,"线程B");
thread1.start();
thread2.start();
}
}
2.synchronized 修饰静态方法
package test;
public class Test2 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable(){
@Override
public void run() {
Test2.test();
}
});
thread.start();
}
}
public static void test(){
System