一 概念
进程:一个程序进入内存运行,即变成一个进程
线程 :一个线程可以有多个进程(一个程序可以同时执行很多任务)
二线程的实现
2.1 继承 Thread类,此类称为多线程的实现类;
格式
class 类名 extends Thread{
属性…;
方法…;
//重写run()方法
public void run(){
}
}
2.2 实现Runable接口;
格式
class 类名 implements Runable{
属性…;
方法…;
//重写接口中的run()
public void run(){
}
}
三线程的操作方法
3.1 开始线程
void | start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
3.2 取得和设置线程名称
String | getName() 返回该线程的名称。 |
void | setName(String name) 改变线程名称,使之与参数 name 相同。 |
3.3判断线程是否启动
boolean | isAlive() 测试线程是否处于活动状态。 |
3.4线程休眠与中断
static void | sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
void | interrupt() 中断线程。 |
3.5优先级
void | setPriority(int newPriority) 更改线程的优先级 |
最低优先级 MIN_PRIORITY 1
中等优先级 NORM_PRIORITY 5
最高优先级 MAX_PRIORITY 10
3.6其他
static Thread | currentThread() 返回对当前正在执行的线程对象的引用 |
static void | yield() 暂停当前正在执行的线程对象,并执行其他线程。 |
同步方法有锁吗?,
肯定有,同步方法中的对象锁,是本类对象引用this
如果方法是静态的呢?
绝对不是this,锁是 本类自己.class 属性
Eg
public static void payTicket(){
Synchronized(Tickets.class){
}
}
(类的加载器与反射时讲)
五死锁
同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。
死锁:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。
这时容易引发一种现象:程序出现无限等待,这种现象我们称之为死锁
前提: 必须是多线程的出现同步嵌套
六等待唤醒机制:
通过一定的手段使各个线程能够有效的利用资源。这种手段称为--等待唤醒机制
线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却是不同。
等待唤醒机制所涉及到的方法:
- wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
- notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
- notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
- 27-16课程
public void run(){
while(true){
if(i%2==0){
//先进入A同步,再进入B同步
synchronized(LockA.lockA){
System.out.println("if...locka");
synchronized(LockB.lockB){
System.out.println("if...lockb");
}
}
}else{
synchronized(LockB.lockB){
System.out.println("else...lockb");
synchronized(LockA.lockA){
System.out.println("else...locka");
//先进入B,再进入A
}
i++;
}
}
实现代码
1
public class Resource {
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name, String sex) {
if (flag)
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 设置成员变量
this.name = name;
this.sex = sex;
// 设置之后,Resource中有值,将标记该为 true ,
flag = true;
// 唤醒output
this.notify();
}
public synchronized void out() {
if (!flag)
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出线程将数据输出
System.out.println("姓名: " + name + ",性别: " + sex);
// 改变标记,以便输入线程输入数据
flag = false;
// 唤醒input,进行数据输入
this.notify();
}
}
2
public class Input implements Runnable {
private Resource r;
public Input(Resource r) {
this.r = r;
}
@Override
public void run() {
int count = 0;
while (true) {
if (count == 0) {
r.set("小明", "男生");
} else {
r.set("小花", "女生");
}
// 在两个数据之间进行切换
count = (count + 1) % 2;
}
}
}
3
public class Output implements Runnable {
private Resource r;
public Output(Resource r) {
this.r = r;
}
@Override
public void run() {
while (true) {
r.out();
}
}
}
4
public class ResourceDemo {
public static void main(String[] args) {
// 资源对象
Resource r = new Resource();
// 任务对象
Input in = new Input(r);
Output out = new Output(r);
// 线程对象
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
// 开启线程
t1.start();
t2.start();
}
}
总结
多个线程想保证线程安全,必须要使用同一个锁对象
synchronized (锁对象){
可能产生线程安全问题的代码
}
同步代码块的锁对象可以是任意的对象
public synchronized void method()
可能产生线程安全问题的代码
}
同步方法中的锁对象是 this
public synchronized void method()
可能产生线程安全问题的代码
}
静态同步方法中的锁对象是 类名.class
a, 继承Thread类
b, 实现Runnable接口
c, 通过线程池,实现Callable接口
a,同步代码块
b,同步方法
静态同步方法
启动一个线程是start()
区别:
start: 启动线程,并调用线程中的run()方法
run : 执行该线程对象要执行的任务
sleep: 不释放锁对象, 释放CPU使用权
在休眠的时间内,不能唤醒
wait(): 释放锁对象, 释放CPU使用权
在等待的时间内,能唤醒
- sleep()和wait()方法的区别
- 启动一个线程是run()还是start()?它们的区别?
- 同步有几种方式,分别是什么?
- 多线程有几种实现方案,分别是哪几种?
- 静态同步方法
- 同步方法
- 同步代码块
- 同步锁