目录
多线程:
在一个应用程序中,存在多个线程,不同的线程可以并行执行任务。
多线程优点:
-
提高程序的处理能力
比如:杀毒软件
-
垃圾清理 1分钟。
-
病毒查杀 1分钟。
-
-
提高cpu利用率
-
大任务的拆分(任务管理器)
-
多线程的缺点:
-
线程越多占用内存越多(硬件升级解决)
-
多个线程之间同时对共享资源进行访问,会出现线程安全问题。
解决方法:多线程同步
加锁:一次只能有一个线程访问共享资源
加锁方式一:synchronized()
继承Thread()
-
修饰代码块
synchronized修饰代码块
synchronized(同步对象/锁){
}
同步对象:对多个线程对应的对象必须是用一个,用来记录有没有线程进入到同步代码块中的;同步对象可以是java中的任何类的对象。
当synochronized对应的对象是多个时
相当于创建了多把锁,还是会出现安全问题。但是可以创建一个公用的同步对象来占用线程。
public class TicketThreadText { public static void main(String[] args) { TicketThread t1=new TicketThread(); t1.setName("窗口1"); TicketThread t2=new TicketThread(); t2.setName("窗口2"); t1.start(); t2.start(); } } public class TicketThread extends Thread{ static int t=10;//无法解决可能会同时进入run方法导致t都是10进入 static byte[] bytes=new byte[0];//没有特殊意义的锁只为了实现多个对象同步//当第二个对象引用bytes时会被锁住等待第一个bytes进行 /*synchronized修饰代码块 同步对象:对多个线程对应的对象必须是用一个,用来记录有没有线程进入到同步代码块中的; 同步对象可以是java中的任何类的对象。 synchronized(同步对象){ }*/ @Override public void run() { while(true){ synchronized(bytes) { if (t > 0) { System.out.println(Thread.currentThread().getName() + "买到了第章" + t + "票"); t--; } else { break; } } } } }
-
修饰方法
synchronized修饰方法,同步对象会有默认的。
修饰的是非静态方法,那么同步对象就是this。
修饰的是静态方法,那么同步对象就是当前类的Class对象。
当前类的class对象:一个类加载到内存会,会为这个类创建一个唯一的Class类对象
public class SynchronizedForTicketThread extends Thread{ static int t=10; @Override public void run() { thread(); } static public synchronized void thread() { while(true) { if(t<=0) { break; } else{ System.out.println(Thread.currentThread().getName()+"买了第"+t+"章票"); t--; } } } } public class TicketThreadText { public static void main(String[] args) { SynchronizedForTicketThread t1=new SynchronizedForTicketThread(); t1.setName("窗口1"); SynchronizedForTicketThread t2=new SynchronizedForTicketThread() ; t2.setName("窗口2"); t1.start();z t2.start(); } }
实现Runnable接口
不需要使用静态方法只有一个任务对象
所以直接使用synchronized修饰即可
-
修饰代码块
public class RunnableForTicketThread implements Runnable {
int t=10;
@Override
public void run() {
while(true)
{
synchronized (this) {
if (t > 0) {
System.out.println(Thread.currentThread().getName() + "出了第" + t + "章票");
t--;
} else {
break;
}
}
}
}
}
public class RunnableTxet {
public static void main(String[] args) {
RunnableForTicketThread runnableForTicketThread=new RunnableForTicketThread();
Thread thread1=new Thread(runnableForTicketThread,"窗口一");
Thread thread2=new Thread(runnableForTicketThread,"窗口二");
thread1.start();
thread2.start();
}
}
-
修饰方法
public class SynchronizedRunnableForTicket implements Runnable{ int t=10; @Override public void run() { thread(); } public synchronized void thread() { while(true) { if(t>0) { System.out.println(Thread.currentThread().getName() + "买到了第" + t + "张票"); t--; } else {break;} } } } public class RunnableTxet { public static void main(String[] args) { SynchronizedRunnableForTicket synchronizedRunnableForTicket=new SynchronizedRunnableForTicket(); Thread thread1=new Thread(synchronizedRunnableForTicket,"窗口一"); Thread thread2=new Thread(synchronizedRunnableForTicket,"窗口二"); thread1.start(); thread2.start(); } }
以上的程序运行结果:
加锁方式二:reentrantLock实现加锁
public class ReentrantLookForTicketRunnable implements Runnable{
int t=10;
ReentrantLock reentrantLock=new ReentrantLock();
@Override
public void run() {
while(t>1) {
reentrantLock.lock();
try {
System.out.println(Thread.currentThread().getName()+"买到了第"+t+"张票");
t--;
} finally {
reentrantLock.unlock();
}
}
}
}
public class ReentrantLookText {
public static void main(String[] args) {
ReentrantLookForTicketRunnable reentrantLookForTicketRunnable = new ReentrantLookForTicketRunnable();
Thread thread1 = new Thread(reentrantLookForTicketRunnable, "窗口一");
Thread thread2 = new Thread(reentrantLookForTicketRunnable, "窗口二");
thread1.start();
thread2.start();
}
}
相同点:都是实现加锁的功能
不同点:
-
Synchronized是一个关键字,ReentrantLock是一个类
-
Synchronized修饰代码块和方法,ReentrantLock只能修饰代码块
-
Synchronized可以隐式的加锁和释放锁,运行过程中出现异常可以自动释放,ReentrantLock需要手动的添加锁和释放锁,建议在finnally代码块中释放锁。