java 多线程和同步
java 多线程
多线程的作用
- 提高资源的利用率
如果当执行单线程的程序时,程序发生阻塞情况,此时的CPU会处于空闲状态;而多线程中,当有一个线程发生阻塞时,CPU会执行其他的进程,从而提高了资源的利用率。 - 简化编程
如果编写一个读取和操作文件的程序时,必须跟踪每个文件的读取和处理状态,相反我们可以创建两个线程,每个线程只读取或处理单个文件,这样不仅可以提高磁盘的利用率,还容编写。、
创建自定义线程的两种方式
- 自定义线程类,继承Thread类,重写run方法
创建自定义线程对象,直接调用start方法,开启线程
class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("继承Thread类自定义线程类");
}
}
}
//在main方法中
MyThread1 myThread1 = new MyThread1();
myThread1.start();
- 自定义线程类,遵从Runnable接口
使用自定义遵从接口Runnable实现类对象,作为Thread构造方法参数,借助于Thread类对象和start方法,开启线程
class MyThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("遵从Runnable接口实现自定义线程类");
}
}
}
//在main方法中
Thread thread = new Thread(new MyThread2());
// 借助于Thread类内的start方法开启线程
thread.start();
Thread 中的方法
构造方法名 | 作用 |
---|---|
Thread() | 无目标,无指定名字 |
Thread(Runnable target); | 创建线程对象的过程中,使用Runnable接口的实现类 |
Thread(String name); | 无目标,有名字 |
Thread(Runnable target, String name); | 使用Runnable接口实现类对象,作为执行目标,并且指定name作为线程名 |
成员方法 | 作用 |
---|---|
void setName(String name);String getName(); | name的getter 和 Setter 方法 |
void setPriority(int Priority); | 设置线程的优先级 [1 ~ 10] |
int getPriority(); | 获取线程优先级 |
void start(); | 启动线程对象 |
public static void sleep(int ms); | 对应进程进行休眠操作。单位毫秒 |
public static Thread currentThread(); | 获取当前所处代码块对应的线程对象 |
线程安全问题和解决方案
举例来说,一个电影有100张票,有3个出售平台,实现这个案例
class SingleThread implements Runnable {
private static int ticket = 100;
@Override
public void run() {
while (true) {
// a
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "售出了" + ticket + "张票");
ticket -= 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "售罄!");
break;
}
//b
}
}
}
//在main方法中
Thread thread1 = new Thread(new SingleThread(), "淘票票");
Thread thread2 = new Thread(new SingleThread(), "猫眼");
Thread thread3 = new Thread(new SingleThread(), "美团");
thread1.start();
thread2.start();
thread3.start();
但是在运行的结果中,我们会发现同一张票被出售了不止一次,为了解决这种问题,我们引入了“锁”机制。
synchronized
while (true) {
synchronized("锁") {
//此处是上面的ab范围内的代码
}
}
通过这种方式我们可以解决上面出现的问题
三种加锁的方式
- 同步方法由static修饰,所以在main方法中可以使用多个目标
//main方法中
Thread thread1 = new Thread(new SingleThread3(), "淘票票");
Thread thread2 = new Thread(new SingleThread3(), "猫眼");
Thread thread3 = new Thread(new SingleThread3(), "美图");
thread1.start();
thread2.start();
thread3.start();
- 同步方法是非静态成员方法时,这个时候只能使用单目标
// main方法中
SingleThread2 singleThread2 = new SingleThread2();
Thread thread1 = new Thread(singleThread2, "淘票票");
Thread thread2 = new Thread(singleThread2, "猫眼");
Thread thread3 = new Thread(singleThread2, "美图");
thread1.start();
thread2.start();
thread3.start();
- Lock 锁
private static int ticket = 100;
//定义一个成员变量
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
//在 a 的位置添加
lock.lock();
/*
* ab之间的代码
*/
lock.unlock();
}
}