程序:一段静态的代码
进程:正在运行的一个程序,系统在运行时为每一个进程分配不同的内存区域。
线程:进程的进一步细化,与进程共享一个内存区域,但是有独立的运行栈和程序计数器。
单核CPU:假的多线程,一个线程执行一次,时间间隔较短,类似多车道,一个收费站。
多核CPU:更好的发挥多线程的效率。
一个java程序至少有三个线程:main()、gc()垃圾回收、异常处理线程。
并行:多个CPU执行多个任务
并发:一个CPU执行多个任务,如:秒杀,多人做同一件事
多线程的优点:
方式一:继承于Thread
start()方法:①启动该线程 ②调用run()方法
注意:
方式二:实现Runnable接口
MAX_PRIORITY :10
NORM_PRIORITY :5 默认优先级
MIN_PRIORITY :1
注意:高优先级的线程要抢占低优先级的线程cpu执行权,但是只是从概率上讲,并不是一定。
getPriority(): 获取
setPriority();设置
开发中,优先选择实现Runnable接口的方式。
原因:
在java中,我们通过同步机制,来解决线程的安全问题。
同步的方式:
好处:解决了线程的安全问题
局限性:操作同步代码时,只有一个线程能操作,效率比较低。
方式一:同步代码块
synchronized(同步监视器){
//需要被同步的代码
}
说明:
方式二:同步方法
操作共享数据的代码完整声明在一个方法中,可使用同步方法的方式。
实现Runnable接口的方式
public synchronize void a(){
}
继承Thread的方式
public static synchronize void a(){
}
注意:
改写单例模式中的懒汉式为线程安全:
class Bank{
private Bank(){}
private static Bank instance = null;
private static Bank getInstance(){
if (instance == null){
synchronized (Bank.class){
if (instance == null){
instance = new Bank();
}
}
}
return instance;
}
}
理解:不同线程占用对方需要的资源不释放,处于僵持的状态,都在互相等待。
说明:出现死锁后程序并不会出现异常,只是所有线程都处于阻塞的状态。
解决方法:
Lock锁-----jdk5.0新增
实例化 ReentrantLock()对象
ReentrantLock lock = new ReentrantLock();
调用锁定方法lock.lock();
解锁lock.unlock();
synchronize 与 Lock 异同? (面试题)
相同:都可以解决线程安全问题
不同:synchronize 机制在执行完相应的同步代码后,自动释放锁。
? Lock需要手动上锁(lock())和解锁(unLock());
使用顺序(建议/非必须)
Lock-->同步代码块-->同步方法
如何解决线程安全问题?有几种方式?(面试题)
三种:同步块,同步方法,锁Lock
线程通信的三个方法:
注意:
public class Test {
public static void main(String[] args) {
Number number = new Number();
Thread t1 = new Thread(number);
Thread t2 = new Thread(number);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
class Number implements Runnable{
int number = 1 ;
@Override
public void run() {
while (true){
synchronized (this) {
notify();
if (number<=100){
System.out.println(Thread.currentThread().getName()+":"+number);
number++;
}
else{
break;
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
产品小于0个不能购买,大于0个可购买。
产品大于20不能再生产,不足20继续生产。
销售类
class Clerk{
private int num = 0;
public synchronized void produceProduct() {
if(num<20){
num++;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":开始生产第"+num+"个产品");
notify();
}else{
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void customerProduct() {
if(num>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":开始消费第"+num+"个产品");
num--;
notify();
}else{
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
生产者
class Producter extends Thread{
private Clerk clerk;
public Producter(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
while (true){
clerk.produceProduct();
}
}
}
消费者
class Customer extends Thread{
private Clerk clerk;
public Customer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
while (true){
clerk.customerProduct();
}
}
}
测试
public class ProductTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producter p1 = new Producter(clerk);
Customer c1 = new Customer(clerk);
Customer c2 = new Customer(clerk);
p1.setName("生产者1");
c1.setName("消费者1");
c2.setName("消费者2");
p1.start();
c1.start();
c2.start();
}
}
JDK5.0 新增
与实现runnable接口相比更加强大:
步骤:
思路:提前建立好多个线程,放入线程池,随用随取。
好处:①提高响应速度②降低资源消耗
③便于线程管理:
步骤:
//1.提供指定数量的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//2.执行指定线程操作,需要提供实现runnable/callable类的对象
executorService.execute(new Number());
//executorService.submit(callable callable);
//3.关闭线程池
executorService.shutdown();
4种:继承Tread
实现Runnable
实现Callable
线程池
原文:https://www.cnblogs.com/xiaolaodi1999/p/13385062.html