一。线程
1.匿名内部类方式实现线程
public class NmThred {
public static void main(String[] args) {
Thread t=new Thread("kk"){//匿名内部类来构造Thread线程对象
public void run() {
Thread t=Thread.currentThread();
for(int i=0;i<10;i++){
System.out.println(t.getName()+i);
}
}
};
t.start();
Runnable run=new Runnable() {//通过匿名内部类来构造初始化Runnable线程任务
@Override
public void run() {
Thread t=Thread.currentThread();
for(int i=0;i<10;i++){
System.out.println(t.getName()+i);
}
}
};
Thread tt=new Thread(run,"lll");//线程任务来创建线程对象
tt.start();
}
}
线程的执行顺序, 是不固定的
线程Thread的构造方法:
1.new 自定义线程类();自定义类的构造方法, 随意
2.new Thread(); 无参构造器
3.new Thread(String); String->指定的线程名
4.new Thread(Runnable); Runnable->线程任务
5.new Thread(Runnable, String);Runnable->线程任务, String->指定的线程名
2.线程Thread常用API:
- 1.static Thread currentThread(): 获得当前正在执行的线程对象
2.String getName(): 获得线程对象的名字, 线程在创建时可以指定名字, 也可以默认分配名字
3.int getPriority(): 返回此线程的优先级
void setPriority(int): 设置线程的优先级
4.boolean isDaemon(): 测试这个线程是否是守护线程
void setDaemon(boolean): 设置这个线程是守护线程
5.static void sleep(long): 线程休眠指定时间
会有一个已检查异常, 所以必须要 try-catch
6.void join(): 等待调用这个方法的线程结束, 再继续后续代码
会有一个已检查异常, 所以必须要 try-catch
7.static void yield(): 主动放弃cpu的时间片
3.优先级:改变CPU分配时间片的概率,只是概率提升,本质上没啥用
public class Demo {
public static void main(String[] args) {
Runnable run = new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
for (int i = 0; i < 10; i++) {
System.out.println(t.getName() + ": " + i);
}
}
};
Thread t1 = new Thread(run, "线程1");
Thread t2 = new Thread(run, "线程2");
Thread t3 = new Thread(run, "线程3");
// 默认优先级, 都是5
/*System.out.println("t1: " + t1.getPriority());
System.out.println("t2: " + t2.getPriority());
System.out.println("t3: " + t3.getPriority());*/
t1.setPriority(Thread.MIN_PRIORITY);
t3.setPriority(10); // 最大优先级
t1.start();
t2.start();
t3.start();
}
}
4.线程延迟、守护线程
守护线程 - 前台线程
当所有的前台线程结束, 守护线程也会自动结束
public class ThreadApi {
public static void main(String[] args) {
Runnable run1=new Runnable() {
@Override
public void run() {
for(int i=0;i<50;i++){
try {
Thread.sleep(100);//制造延迟, 让线程暂停一下
}catch (Exception e){
}
System.out.println("块跳");
}
System.out.println("我跳了,你骗我");
}
};
Runnable run2=new Runnable() {
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
}catch (Exception e){}
System.out.println("you jump i jump");
}
}
};
Thread t1=new Thread(run1,"lucy");
Thread t2=new Thread(run2,"jack");
System.out.println("是否为守护线程"+t2.isDaemon());//判断是否为守护线程
t2.setDaemon(true);//设置为守护线程。守护线程会在前台线程结束后结束
t1.start();
t2.start();
}
}
5.线程同步 - 多个线程, 共享资源
1.synchronized: 同步锁, 只能同时被一个线程持有,
当线程执行完这个方法, 才会将锁释放
加到方法上, 同步方法锁
加到代码上, 借助对象, 通常是this,
确保同步的线程, 对象共享即可
2.Lock - 接口
实现类: ReentrantLock lock = new ReentrantLock();
加锁: 锁对象.lock();
解锁: 锁对象.unlock();
public class Ticket {
public int count=100;
//①synchronized在方法上加锁,(同步方法锁)。使线程安全
/*public synchronized void saleTicket(){
if(count==0){
throw new RuntimeException("票无!");
}
System.out.println(Thread.currentThread().getName()+count);
count--;
}*/
//②synchronized对象锁
/*public void saleTicket(){
synchronized (this){
if(count==0){
throw new RuntimeException("票无!");
}
System.out.println(Thread.currentThread().getName()+count);
count--;
}
}*/
//③Lock锁
ReentrantLock lock=new ReentrantLock();//创建lock锁对象
public void saleTicket(){
// ReentrantLock lock=new ReentrantLock();//创建lock锁对象
lock.lock();//上锁
if(count==0){
throw new RuntimeException("票无!");
}
System.out.println(Thread.currentThread().getName()+count);
count--;
lock.unlock();//开锁
}
}
synchronized使用原则: 尽量将少的代码加锁
可以只将一部分代码加锁, 同步代码锁, 需要借助一个对象
加锁的对象: 可以是任意对象, 只需要确保多个同步的线程, 对象唯一就可以了
通常使用this对象
对象锁: 一个对象只能加一把锁, 并且只能同时被一个线程持有
6. 图片加载和显示两个线程:
- List item 1.线程1 负责图片的加载任务. 1%~100% -> 加载完成
2.线程2 负责图片的显示任务. 要求图片加载完才能显示
线程1 和 线程2 是同时开启的 start()
public class Demo {
public static void main(String[] args) {
Picture picture = new Picture();
Thread load = new Thread(){
public void run() {
System.out.println("图片开始加载....");
for (int i = 0; i < 100; i++) {
System.out.println("正在加载: " + (i+1) + "%");
}
System.out.println("图片加载完成");
}
};
Thread show = new Thread(){
public void run() {
System.out.println("等待图片加载完成....");
// 等待 load 线程结束
try {
load.join();//join可以可以阻塞此部分程序
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("显示图片!");
}
};
load.start();
show.start();
}
}
二。线程通信:
两个线程有共享数据, 线程之间有动作交互
wait(): 等待
notify(): 唤醒
①.
- 图片加载/下载 和 图片显示两个线程:
1.线程1 先负责图片的加载任务. 1%~100% -> 加载完成
再负责图片的下载任务. 1%~100% -> 下载完成
要求图片显示完才能下载
2.线程2 负责图片的显示任务. 要求图片加载完才能显示
public class Load extends Thread {
Picture picture;
public Load(Picture picture, String name) {
super(name);
this.picture = picture;
}
@Override
public void run() {
//图片开始加载
System.out.println("图片开始加载");
for(int i=0;i<100;i++){
System.out.println("图片加载了"+i+"%");
}
System.out.println("图片加载完成");
//加载完图片修改lode状态
picture.isLoad=true;
加载好要唤醒show
synchronized (picture){
picture.notify();
}
//等待图片显示完成
if(!picture.isShow){
synchronized (picture){
try {
picture.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//图片显示 notif,开始下载图片
System.out.println("开始下载图片...");
if(picture.isShow){
for (int i=0;i<100;i++){
System.out.println("图片正在下载"+i+"%");
}
}
System.out.println("图片下载完成");
}
}
public class Show extends Thread{
Picture picture;
public Show(Picture picture, String name) {
super(name);
this.picture=picture;
}
@Override
public void run() {
System.out.println("等待图片加载完成....");
//图片没加载完
if(!picture.isLoad){
synchronized (picture){
try {
picture.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//图片加载完成,显示图片
System.out.println("显示图片");
if(picture.isLoad){
try {
Thread.sleep(3000);//图片显示3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//改变图片显示状态
picture.isShow=true;
//图片显示完成,开始下载,唤醒下载线程
synchronized (picture){
picture.notify();
}
}
}
public class Picture {
public boolean isLoad;
public boolean isShow;
}
public class Main {
public static void main(String[] args) {
Picture picture=new Picture();
Load load=new Load(picture,"load");
Show show=new Show(picture,"show");
load.start();
show.start();
}
}