01----线程,进程相关概念
- 进程:进程是指运行中的程序,是程序的一次执行过程。
- 线程:线程由进程创建,是进程的一个实体,一个进程可以有多个线程
- 线程也可以创建线程
02----并发,并行
- 单线程:同一时刻,只允许执行一个线程
- 多线程:同一时刻,可以执行多个线程
- 并发:同一时刻,多个任务交替执行,造成一种“貌似同时”的错觉,如单核CPU实现多任务
- 并行:同一时刻,多个任务同时执行
03----线程的创建方式
- 继承
Thread
类 - 实现
Runnable
接口 - 启动多线程必须调用
start()
方法
//方式一:
public class ThreadTest01 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start(); //启动多线程必须调用start()方法
}
}
class Cat extends Thread{
@Override
public void run() {
super.run(); //这里根据要求重写方法体
}
}
// 方式二:
public class RunnableTest01 {
public static void main(String[] args) {
Dog dog = new Dog();
new Thread(dog).start(); //代理模式:静态代理
}
}
class Dog implements Runnable{
@Override
public void run() {
}
}
05----为什么调用start()方法?
start()
调用本地方法(native)方法start0()
,真正实现多线程的是start0()
方法start()
调用start0()
方法后,该线程并不一定会立即执行,只是将线程变成了可运行状态,具体什么时候执行取决于CPU,由CPU统一调度
08----多线程售票问题(多个线程操作同一个对象)
public class SellTickets {
public static void main(String[] args) {
Tickets tickets1 = new Tickets();
Tickets tickets2 = new Tickets();
Tickets tickets3 = new Tickets();
tickets1.start();
tickets2.start();
tickets3.start();
}
}
class Tickets extends Thread{
int numTickets = 20;
@Override
public void run() {
while (true){
if (numTickets <= 0){
break;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "卖出了一张票,剩余:" + (--numTickets));
}
}
}
10----线程的方法
- interrupt:中断,不是退出
- sleep:休眠
- start:
- yield:礼让,不一定成功
- join:插队,插入成功则一直执行到完毕
13----守护线程
- 用户线程:也叫工作线程,当线程的任务执行完或者以通知方式结束
- 守护线程:一般是为工作线程服务的,当所有用户线程结束,守护线程自动结束,如垃圾回收机制
MyDaemonThread t1 = new MyDaemonThread; //Daemon:守护
t1.setDaemon(true);
t1.start();
14----线程的7大状态
- NEW:新建
- RUNNABLE:可运行
- Ready:就绪
- Running:运行
- BLOCKED:阻塞
- WAITING:等待
- TIMED_WAITING:超时等待,如sleep
- TERMINATED :终止
15----线程的同步
互斥锁:保证数据的完整性。
synchronized
:1. 同步方法, 2. 同步代码块
互斥锁注意事项:
-
// 同步方法(非静态)的锁可以是this,也可以是其他对象(要求是同一个对象);
-
// 同步方法(静态的)的锁只能是当前类本身;
-
多个线程的锁必须是同一个。
//------------------同步方法------------------------
/*
* 多个线程同时操作一个对象
* 买火车票的例子
*
* 发现问题:多个线程操作一个对象,线程不安全,数据紊乱
* */
public class SellTickets03 implements Runnable{
int ticketNum = 10;
boolean loop = true;
@Override
public void run() {
while (loop) {
sell();
}
}
public synchronized void sell(){
if (ticketNum<=0){
loop = false;
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 拿到了第 " + ticketNum-- + " 票");
}
public static void main(String[] args) {
SellTickets03 ticket = new SellTickets03();
new Thread(ticket).start();
new Thread(ticket).start();
new Thread(ticket).start();
}
}
public class SellTickets02 {
public static void main(String[] args) {
Tickets02 tickets1 = new Tickets02();
new Thread(tickets1).start();
new Thread(tickets1).start();
new Thread(tickets1).start();
}
}
//------------------同步代码块------------------------
class Tickets02 implements Runnable{
private int numTickets = 10;
boolean loop = true;
public void sell(){
synchronized (this){ // 同步方法(非静态)的锁可以是this,也可以是其他对象(要求是同一个对象);
// 同步方法(静态的)的锁只能是当前类本身;
if (numTickets <= 0) {
loop = false;
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余:" + --numTickets);
}
}
@Override
public void run() {
while (loop){
sell();
}
}
}
17----线程死锁
多个线程互相抱着对方需要的资源,然后形成僵持
某一个同步块同时拥有”两个以上对象的锁“时,就有可能发生死锁问题,如下:
if(...){
synchronized (lock1){
.............
synchronized (lock2){
..........
}
}
}else{
synchronized (lock2){
.............
synchronized (lock1){
..........
}
}
}
18----释放锁
- 下面情况会释放锁
- 当前线程的同步方法,同步代码块执行结束
- 当前线程的同步方法,同步代码块遇到break,return
- 当前线程在同步方法,同步代码块中出现了未处理的error或exception,导致异常结束
- 当前线程在同步方法,同步代码块中执行了线程对象的wait()方法,当前线程暂停,并释放锁
- 下面情况不会释放锁
- 线程执行同步方法,同步代码块时,程序掉哦用了sleep()方法,yield()方法暂停当前线程的执行,不会释放锁
- 线程执行同步代码块,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁
19----作业
import java.util.Locale;
import java.util.Scanner;
public class Homework01 {
/*
* 在main中启动两个线程
* 线程a循环随机打印100以内的整数
* 直到线程b从键盘读入“Q”停止 (因此,b得有a的对象)
* */
public static void main(String[] args) {
A a = new A();
B b = new B(a);
a.start();
b.start();
}
}
class A extends Thread{
boolean loop = true;
@Override
public void run() {
while (loop){
System.out.println((int)(Math.random()*100+1));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程a已推出");
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
class B extends Thread{
A a;
Scanner scanner = new Scanner(System.in);
public B(A a) {
this.a = a;
}
@Override
public void run() {
//System.out.println("线程b已开启,输入Q停止线性a:");
while (true){
System.out.println("线程b已开启,输入Q停止线性a:");
if (scanner.next().toUpperCase().charAt(0) == 'Q'){
a.setLoop(false);
System.out.println("线程b已退出");
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
作业二:
public class Homework02 {
/*
* 有两个用户在同一个卡上取钱(总额:1w)
* 每次都取1000,当余额不足时,就不能再取款
* 线程同步问题
* 多个线程共享资源,优先选取Runnable方式
* */
public static void main(String[] args) {
T t = new T();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.setName("Xiaoming");
t2.setName("Dazhuang");
t1.start();
t2.start();
}
}
class T implements Runnable{
private int money = 10000;
@Override
public void run() {
while (true) {
synchronized (this){ // 加锁
if (money <= 0) {
break;
}
money = money - 1000;
System.out.println(Thread.currentThread().getName() + "取走了1000元,现在余额为:" + money);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}