1、多线程
1.2进程和线程
进程
正在运行的程序的实例
线程
进程的执行单元
1.3继承Thread类实现多线程
1.定义一个类,继承Thread类
2.重写run方法,设置线程任务
3.创建线程任务类对象
4.通过线程任务类对象调用start方法,开启线程
1.4设置和获取线程名称
1.4.1设置
Threa(String name)
通过Thread类的构造方法设置
void setName(String name)
通过Thread类的setName方法设置
1.4.2获取
String getName()
通过Thread类的成员方法getName获取
Thread.currentThread().getName()
通过Thread类的静态方法获取当前线程对象,之后再获取线程名称
package com.itfenghua01;
//继承线程,重写run方法,实现构造方法
public class myThream extends Thread {
public myThream(){}
public myThream(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 99; i++) {
System.out.println(getName()+","+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
----------------------------------
package com.itfenghua01;
public class threadDemo {
public static void main(String[] args) {
myThream mt1 = new myThream("石");
myThream mt2 = new myThream();
mt2.setName("玉");
String name = Thread.currentThread().getName();
System.out.println(name);
mt1.start();
mt2.start();
}
}
1.5设置和获取线程优先级
void setPriority(int newPriority)
设置线程优先级,从1到10,越来越高,默认是5
int getPriority()
获取线程的优先级
1.6线程控制
void sleep(long time)
让当前线程休眠指定时间
void join()
等待当前线程终止
void setDaemon(boolean on)
将当前线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
1.7线程生命周期
新建
就绪
运行
阻塞
死亡
1.8实现Runnable接口实现多线程
1.8.1步骤
1.定义一个类,实现Runnable接口
2.重写run方法,设置线程任务
3.创建任务类对象
4.创建线程类对象,构造方法传入任务类对象
5.通过线程类的start方法,开启线程
1.8.2好处
1.避免了单继承的局限性
2.降低了程序的耦合性,提高了程序的拓展性
2、线程安全
2.1线程安全问题产生原因
1.是多线程
2.有共享数据
3.有多条语句操作共享数据
2.2同步代码块
2.2.1格式
synchronized(锁对象){
//多条语句操作共享数据的代码
}
2.2.2锁对象
Object obj = new Object
任意对象
this
当前对象
类名.class
对应的类的Class对象(一个类的Class对象多次获取是同一个)
注意
要保证线程安全,多个线程必须使用同一把锁
2.2.3好处和弊端
好处:解决了多线程的数据安全问题
弊端:频繁的判断锁,获取锁,释放锁,会降低程序的运行效率
package com.itfenghua03;
public class shellTekits implements Runnable {
private static int tickits = 100;
//表示任意对象
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickits > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickits + "张票");
tickits--;
} else {
// shelltt();
shellkk();
}
}
}
}
//类名.class全局只有一个做锁
private static synchronized void shellkk() {
if (tickits > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickits + "张票");
tickits--;
}
}
//锁使用this代表同一把锁
private void shelltt() {
synchronized (this)
{
if (tickits > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickits + "张票");
tickits--;
}
}
}
}
2.3同步方法
2.3.1格式
修饰符 synchronized 返回值类型 方法名(){
//多条语句操作共享数据的代码
}
2.3.2注意事项
1.普通同步方法的锁对象是this
2.静态同步方法的锁对象是类名.class
2.4Lock锁
2.4.1介绍
JDK1.5之后出现的,在产生安全问题代码前获取锁,在产生安全问题代码后释放锁
2.4.2使用步骤
Lock lock = new ReentrantLock()
创建锁对象
lock.lock()
获取锁对象
lock.unlock()
释放锁对象
2.4.3注意
任何情况下都要释放锁对象
package cx.itfenghua02;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class lockRun implements Runnable{
private int tickets = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if (tickets>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets+"斤猪肉");
tickets--;
}else {
break;
}
lock.unlock();
}
}
}
3、等待与唤醒
3.1方法
void wait()
让当前线程进入等待状态
void notify()
唤醒在此对象监视器上等待的单个线程
void notifyAll()
唤醒在此对象监视器上等待的所有线程
3.2注意事项
1.可以使用任意对象调用wait和notify方法,因为任意对象都继承Object
2.必须使用锁对象并且是同一把锁对象调用wait和notify才有意义
3.必须在同步方法或者同步代码块内调用wait和notify才有意义