中午说的笔记来辣:
(
main线程会走完之后再走run的线程
当run线程加入join后就会把run线程走完再走
static修饰的东西在线程中层级相当于一个类方法
Thread t=new Thread(new FutureTask(new 类()),"");
Thread.State state = t.getState();
state是观察该线程是否运动,线程一旦死亡就无法再执行
)(括号的内容是小编在复习笔记中觉得较重要的,不喜滑走)
====================================================》
线程锁
synchronized和ReentrantLock的区别
Synchronized
例:
public synchronized void save(){}//static方法就是类锁,如果是非static则是对象锁;
synchronized (TestObject.class) {}//此处是类锁,无论怎么创建对象,都不会对同步代码块产生影响,因为所有的对象都是用的同一把锁;
1、该案例是多个线程“干一个活”,为了防止覆盖和超值,通过对象锁来维持线程秩序
2、怎么通过锁方法维护程序秩序,如果不维护会出现跟1一样的错误
public class TestThread03 {
public synchronized void exec()
{
System.out.println("线程开始:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 3; i++) {
System.out.println("***");
}
System.out.println("线程结束:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
TestThread03 thread03 = new TestThread03();
Thread t1 = new Thread(thread03, "线程1");
t1.exec();
Thread t2 = new Thread(thread03, "线程2");
t2.exec();
Thread t3 = new Thread(thread03, "线程3");
t3.exec();
t1.start();
t2.start();
t3.start();
}
}
3、同样是多个线程“干一个活”,为了防止覆盖和超值
/**
* 对象锁,锁的是对象,如果对象发生了新的变化
* 那么锁也会变成新的锁。
*
*
* 类锁,锁的是类,无论对象怎么变化,锁都不会改变。
* 类锁其实就是无论怎么创建对象,这些对象都共用同一把锁
*
*
*
*/
public class Thread01 implements Runnable {
Object o = new Object();
@Override
public void run() {
/**
* Object o = new Object();
* synchronized(new Object())
* {
*
* }
*
* 以上两种形式都会产生新的对象,每个线程的对象都是新的对象,
* 也就是每个线程拥有不同的对象锁
*
*/
//线程A
synchronized (o)//此处锁的是对象,所以要保证对象的唯一性,不要再创建同类型的对象
{
System.out.println("线程开始:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 3; i++) {
System.out.println("***");
}
System.out.println("线程结束:"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread01 thread01 = new Thread01();
Thread t1 = new Thread(thread01, "线程1");
Thread t2 = new Thread(thread01, "线程2");
Thread t3 = new Thread(thread01, "线程3");
t1.start();
t2.start();
t3.start();
}
}
4、synchronized (TestObject.class)的演示
public class Thread02 implements Runnable {
Object tt = new Object();
@Override
public void run() {
Object tt2 = new Object();
/**
* synchronized (Object.class)
* {
*
* }
* 如果此处锁的是类,那就是类锁,类锁是可以创建无数个对象,但是并
* 不会影响程序的正确性
*
*
*/
//线程A
synchronized (Object.class)// synchronized (this)this表示调用该方法对应的类的对象,this对应的对象是不会发生变化的
{
System.out.println("线程开始:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 3; i++) {
System.out.println("***");
}
System.out.println("线程结束:"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread02 thread02 = new Thread02();
Thread t1 = new Thread(thread02, "线程1");
Thread t2 = new Thread(thread02, "线程2");
Thread t3 = new Thread(thread02, "线程3");
t1.start();
t2.start();
t3.start();
}
}
总结:
synchronized是自动锁,隐式锁
synchronized(this|object)对象锁
synchronized(类的名.class)全局锁
一般情况不建议使用synchronized锁,因为synchronized会降低程序性能
ReentrantLock
ReentrantLock是显式锁,手动开关,需要手动释放
使用ReentrantLock,JVM将会花费更少时间来调度线程,性能更好
例子:
我们通过买票来演示,大家都知道过节有的票是要抢的,但用线程怎么能让票在售票人员中即不会重票又不超票呢?
/**
*
* Lock显式锁,synchronized隐式锁
*
* 区别:
* Lock需要手动设置和手动释放
* synchronized 超出范围后会自动释放
*
* Lock只有代码块锁,synchronized有代码锁,还有方法锁
*
* Lock消耗的时间<synchronized代码块<synchronized方法
*
*
*/
public class Thread04 implements Runnable {
int ticket=100;
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while(true)
{
try {
Thread.sleep(1000);
lock.lock();//开启锁
if(ticket>0)
{
System.out.println("当前售票窗口:"+Thread.currentThread().getName()+"当前票数:"+(ticket--));
}
else
{
System.out.println("售票完毕!");
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();//释放锁
}
}
}
public static void main(String[] args) {
Thread04 th = new Thread04();
Thread t1 = new Thread(th, "窗口1");
Thread t2 = new Thread(th, "窗口2");
Thread t3 = new Thread(th, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
最后补充点小知识
小贴士:run方法和start方法区别:
Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,
就开始执行run()方法,这里的run()方法 称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止