程序:是为完成特定任务、用某种语言编写的一组指令的集合。即一段静态的代码,静态对象。
进程:是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期
线程:进程可进一步细化为线程,是一个程序内部的一条执行路径。
附加:内存的结构

//1. 创建一个继承于Thread的类
class MyThread extends Thread{
//2. 重写Thread类的run()
@Override
public void run() {
for (int i = 0 ;i <= 1000; i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
// 3. 创建Thread类的子类对象
MyThread t1 = new MyThread();
// 4. 通过此类的对象调用start():①启动当前线程 ②调用当前线程的run()
t1.start();
// 问题一:我们不能通过直接调用run()的方式启动线程
// t1.run();
// 问题二:在启动一个线程,编译1000内的偶数,不可以还让已经start()的线程去执行。会报IllegalThreadStateException的异常
// t1.start(); // 报IllegalThreadStateException异常
// 我们需要重新创建一个线程对象
MyThread t2 = new MyThread();
t2.start();
// 如下操作仍然是在main线程执行的
for (int i = 0 ;i <= 1000; i++){
if(i % 2 != 0){
System.out.println(Thread.currentThread().getName() + ": " + "*********main()**********");
}
}
}
}
//1. 创建一个实现了Runnable接口的类
class MThread implements Runnable{
// 2. 实现类去实现Runnable中的抽象方法:run()
@Override
public void run() {
for(int i = 0 ; i <= 100; i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
// 3. 创建实现类的对象
MThread mThread = new MThread();
// 4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread t1 = new Thread(mThread);
// 5. 通过Thread类的对象调用start()
t1.setName("线程1");
t1.start();
Thread t2 = new Thread(mThread);
t2.setName("线程2");
t2.start();
}
}
// 问题一:我们不能通过直接调用run()的方式启动线程
// t1.run();
// 问题二:在启动一个线程,编译1000内的偶数,不可以还让已经start()的线程去执行。会报IllegalThreadStateException的异常
// t1.start(); // 报IllegalThreadStateException异常
// 我们需要重新创建一个线程对象
MyThread t2 = new MyThread();
t2.start();
线程的优先级:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5 --> 默认优先级
如何获取和设置当前线程的优先级
getPriority():获取当前线程
setPriority():设置当前线程
说明:高优先级的线程要抢占低优先级线程的cpu执行权,但是只是从概率上讲,高优先级的线程高概率的情况下呗执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行
class HelloThread extends Thread{
@Override
public void run() {
for(int i = 0; i <= 100; i++){
if(i % 2 == 0){
// try {
// sleep(10);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
System.out.println(Thread.currentThread().getName() + ": " + Thread.currentThread().getPriority() + ": " + i);
}
// if(i % 20 == 0){
// yield();
// }
}
}
// 设置线程名字,方法一:
public HelloThread(String name){
super(name);
}
}
public class ThreadMethodTest {
public static void main(String[] args) {
HelloThread h1 = new HelloThread("Thread一");
// 设置线程名字,方法二:
// h1.setName("线程一");
h1.setPriority(Thread.MAX_PRIORITY);
h1.start();
// 给主线程命名
Thread.currentThread().setName("主线程");
for(int i = 0; i <= 100; i++){
if(i % 2 != 0){
System.out.println(Thread.currentThread().getName() + ": " + Thread.currentThread().getPriority() + ": " + i);
}
// if(i == 20){
// try {
// h1.join();
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// }
}
// System.out.println(h1.isAlive());
}
}

synchronized(同步监视器){
// 需要同步的代码
}
说明:
使用同步方法代码块解决实现Runnable接口的方式的线程安全问题:
class Window2 implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while(true) {
synchronized (this) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + ": 买票,票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
public class WindowTest2 {
public static void main(String[] args) {
Window2 window2 = new Window2();
Thread t1 = new Thread(window2);
Thread t2 = new Thread(window2);
Thread t3 = new Thread(window2);
t1.setName("窗口1:");
t2.setName("窗口2:");
t3.setName("窗口3:");
t1.start();
t2.start();
t3.start();
}
}
使用同步方法代码块解决继承Thread类的方式的线程安全问题:
class Window3 extends Thread{
private static int ticket = 100;
private static Object obj = new Object();
@Override
public void run() {
synchronized (Window3.class){ //类也是个对象,且是唯一的(使用当前类充当同步监视器)
// synchronized (obj) {
while (true) {
if (ticket > 0) {
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName() + ": 买票,票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
public class WindowTest3 {
public static void main(String[] args) {
Window3 t1 = new Window3();
Window3 t2 = new Window3();
Window3 t3 = new Window3();
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
说明: 在继承Thread类创建的的多线程发方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器。
使用同步方法解决实现Runnable接口的方式的线程安全问题:
class Window4 implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
if(ticket <= 0) break;
show();
}
}
private synchronized void show(){ //同步监视器:this
if(ticket > 0){
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
System.out.println(Thread.currentThread().getName() + ": 买票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest4 {
public static void main(String[] args) {
Window4 window4 = new Window4();
Thread t1 = new Thread(window4);
Thread t2 = new Thread(window4);
Thread t3 = new Thread(window4);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
使用同步方法解决继承Thread类的方式的线程安全问题:
class Window5 extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
if(ticket <= 0) break;
show();
}
}
private static synchronized void show(){ //同步监视器:Window5.class
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ": 买票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest5 {
public static void main(String[] args) {
Window5 t1 = new Window5();
Window5 t2 = new Window5();
Window5 t3 = new Window5();
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
package Thread.java;
import java.util.concurrent.locks.ReentrantLock;
/**
* 解决线程安全问题的方式三:Lock锁 --- JDK5.0新增
*
* 1. 面试题:synchronized 于 Lock锁的异同?
* ① 相同:二者都可以解决线程安全问题
* ② 不同:synchronized机制在执行完全相同的同步代码以后,自动释放同步监视器
* Lock需要手动启动同步(lock()),同时结束也需要手动的实现(unlock())
*
* @author XiaoQ
* @create 2022-09-17 22:40
*/
class Window implements Runnable{
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock(true); //按每个线程的顺序执行一次
// private ReentrantLock lock = new ReentrantLock(true); //随机线程执行
@Override
public void run() {
while(true){
try {
lock.lock();
if(ticket > 0){
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
System.out.println(Thread.currentThread().getName() + ": 买票,票号为:" + ticket);
ticket--;
}else{
break;
}
}finally {
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
Window window = new Window();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
package 懒汉式线程安全问题;
/**
* 使用同步机制将单例模式中的懒汉式改写为线程安全的
*
* @author XiaoQ
* @create 2022-09-17 16:37
*/
public class BankTest {
}
class Bank{
private Bank(){}
private static Bank instance = null;
public static Bank getInstance(){
// 方式一:效率稍差
// synchronized (Bank.class){
// if(instance == null){
// instance = new Bank();
// }
// return instance;
// }
//方式二:效率更高
if(instance == null){
synchronized (Bank.class){
if(instance == null){
instance = new Bank();
}
}
}
return instance;
}
}
package Thread.java;
/**
* 演示线程的死锁
* 1. 死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己不需要的同步资源么久形成了线程的死锁
*
* 2.说明:
* ① 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
* ② 我们使用同步时,要避免出现死锁
*
*
* @author XiaoQ
* @create 2022-09-17 16:59
*/
public class DeadLock {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer();
StringBuffer s2 = new StringBuffer();
new Thread(){
@Override
public void run() {
synchronized(s1){
s1.append("a");
s2.append(1);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (s2){
s1.append("b");
s2.append(2);
System.out.println(s1);
System.out.println(s2);
}
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized(s2){
s1.append("c");
s2.append(3);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (s1){
s1.append("d");
s2.append(4);
System.out.println(s1);
System.out.println(s2);
}
}
}
}).start();
}
}
涉及到的三个方法:
说明:
面试题: sleep()和wait()方法的异同?
package Communication;
/**
* 线程通信的例子:使用2个线程打印1 - 100;线程1和线程2交替打印
* 涉及到的三个方法:
* wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
* notify():一旦执行此方法,就会唤醒wait的一个线程;如果有多个线程被wait,就唤醒优先级高的
* notifyAll():一旦被执行此方法,就会唤醒所有被wait的线程
*
* 说明:
* 1. wait()、notify()、notifyAll()三个方法必须使用在同步代码块或同步方法中
* 2. wait()、notify()、notifyAll()三个方法的调用者必须时同步代码块或同步方法中的同步监视器,
* 否则会出现IllegalMonitorStateException异常
* 3. wait()、notify()、notifyAll()三个方法时宏定义在Java.lang.Object类中的
*
* 面试题:sleep()和wait()方法的异同?
* 1. 相同点:一旦执行,都可以使得当前线程进入阻塞状态
* 2. 不同点:① 两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
* ② 调用的要求不同,sleep()可以在任何需要的场景下调用,wait()必须使用在同步代码块或同步方法中
* ③ 关于是否释放同步监视器:如果两个都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁
*
* @author XiaoQ
* @create 2022-09-18 8:56
*/
class Number implements Runnable{
private int num = 1;
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
obj.notify(); //a
if (num <= 100) {
System.out.println(Thread.currentThread().getName() + ": " + num);
num++;
try {
obj.wait(); //调用如下wait()方法的线程进入阻塞状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
break;
}
}
}
}
}
public class CommunicationTest {
public static void main(String[] args) {
Number number = new Number();
Thread t1 = new Thread(number);
Thread t2 = new Thread(number);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
如何理解实现Callable接口的方式创建多线程币实现Runnable接口创建多线程方式强大?
- call()可以有返回值
- call()可以抛出异常,被外面操作捕获,获取异常信息
- Callable时支持泛型的
package 创建线程的方式三和四;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 创建线程方式的三:实现Callable接口(JDK 5.0新增)
*
* 如何理解实现Callable接口的方式创建多线程币实现Runnable接口创建多线程方式强大?
* 1. call()可以有返回值
* 2. call()可以抛出异常,被外面操作捕获,获取异常信息
* 3. Callable时支持泛型的
*
* @author XiaoQ
* @create 2022-09-18 10:57
*/
//1. 创建一个实现Callable的实现类
class NumThread implements Callable{
//2. 实现call()方法,将此线程需要执行的操作声明在call()中
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100 ; i++) {
if(i % 2 == 0){
sum += i;
System.out.println(i);
}
}
return sum;
}
}
public class ThreadNew {
public static void main(String[] args) {
//3. 创建Callable接口实现类的对象
NumThread numThread = new NumThread();
//4. 将此Callable接口的实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
FutureTask futureTask = new FutureTask(numThread);
//5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
new Thread(futureTask).start();
try {
// 6. 获取Callable中call()的返回值
Object sum = futureTask.get(); //get()返回值即为FutureTask构造器参数Callable实现类重写的call()返回值
System.out.println("总和为:" + sum);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
}
好处:
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
- 便于线程管理
① corePoolSize:核心池的大小
② maximumPoolSize:最大线程数
③ keepAliveTime:线程没有任务时最多保持多长时间后会终止
package 创建线程的方式三和四;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 创建线程的方式四:使用线程池
*
* 好处:
* 1. 提高响应速度(减少了创建新线程的时间)
* 2. 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
* 3. 便于线程管理
* corePoolSize:核心池的大小
* maximumPoolSize:最大线程数
* keepAliveTime:线程没有任务时最多保持多长时间后会终止
*
* @author XiaoQ
* @create 2022-09-18 13:24
*/
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 ThreadPool {
public static void main(String[] args) {
//1. 提供指定线程数量的线程池
ExecutorService service = Executors.newFixedThreadPool(10); //提供10线程
//设置线程池的属性
ThreadPoolExecutor service1 = (ThreadPoolExecutor)service;
service1.setCorePoolSize(15);
//2. 执行指定的线程操作,需要提供实现Runnable接口或Callable接口实现类的对象
service.execute(new NumberThread());
service.execute(new NumberThread1());
//3. 关闭线程池
service.shutdown();
}
}