多线程基础
-
特点:代码的运行结果与代码的执行顺序是无关的。因为cup以随机的方式调用线程中的run方法。
-
实现方法:
-
继承thread类
-
实现runnable接口
-
线程方法
-
isAlive():测试线程是否处于活动状态
-
getId():取得线程唯一标识
-
yield():放弃当前的CPU资源
-
currentThread():返回当前线程信息
-
sleep():睡眠时,保持对象锁,仍然占有该锁;
-
wait():睡眠时,释放对象锁
-
interrupted():是类的静态方法,测试当前线程是否已经是中断状态,执行具有将状态标志清除为 false的功能。
-
isInterrupted():是类的实例方法,测试Thread对象是否已经是中断状态,但不清楚状态标志。
线程的优先级
- 继承性. 如,线程A启动线程B,则B和A优先级一样
- 规则性. CPU尽量倾向于把资源优先级高的线程
- 随机性. 优先级不等同于执行顺序,二者关系不确定
用户线程和守护(Daemon)线程。
- 守护线程:进程中不存在非守护线程时,守护线程自动销毁。
synchronized锁
package Thread;
public class Lock_1 {
private int num = 0;
//将方法加上synchronized关键字后,当某线程调用该方法时就会持有锁,其他线程只有
//当该线程调用完该方法后才能调用该方法。优点是增加了线程的安全,缺点也很明显,
//程序的运行效率将降低很多。
synchronized public void addI(String username) {
try {
//int num = 0;
if (username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over");
}
System.out.println(username +"num="+num);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package Thread;
public class Thread_2 extends Thread{
private Lock_1 lock_1;
public Thread_2(Lock_1 lock_1){
super();
this.lock_1 = lock_1;
}
@Override
public void run(){
super.run();
lock_1.addI("a");
}
}
package Thread;
public class Thread_3 extends Thread{
private Lock_1 lock_1;
public Thread_3(Lock_1 lock_1){
super();
this.lock_1 = lock_1;
}
@Override
public void run(){
super.run();
lock_1.addI("b");
}
}
package Thread;
public class Run {
public static void main(String[] args) {
Lock_1 lock_1 = new Lock_1();
Thread_2 a = new Thread_2(lock_1);
a.start();
Thread_3 b = new Thread_3(lock_1);
b.start();
}
}
运行结果:
a set over
anum=100
b set over
bnum=200
但是倘若去掉addI方法前的synchronized运行结果为:
a set over
b set over
bnum=200
anum=200
当a线程进入时,b线程也跟着进入该方法,a线程修改了num的值在sleep时num的值已被b线程修改成了200所以最后a、b线程输出num都为200。
注意:synchronized取得的都是对象锁,而不是将一段代码或者方法当做锁,所以线程安全的前提是多个线程访问的是同一个对象。假如多个线程访问多个对象时,那么jvm就会创建多个锁,那么我们修改下上面代码
public class Run {
public static void main(String[] args) {
Lock_1_1 lock_1 = new Lock_1_1();
Lock_1_1 lock_2 = new Lock_1_1();
Thread_2_1 a = new Thread_2_1(lock_1);
a.start();
Thread_3_1 b = new Thread_3_1(lock_2);
b.start();
}
}
运行结果为:
a set over
b set over
bnum=200
anum=100
可以看到,锁并未起到作用。
synchronized(this)与synchronized(非this)区别
- synchronized(this):以当前类的实例作为锁当一个类中有多个该方法时,执行效率会受到很大的影响。
- synchronized(非this)
synchronized方法加static与不加的区别
- 加static:锁住当前的class类。
- 不加static:锁住当前实例对想。
package Thread;
/**
*
* @author zjq
*/
public class Service {
synchronized public static void printA() {
try {
System.out.println("线程名称是:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程名称是:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printA");
} catch (Exception e) {
e.printStackTrace();
}
}
synchronized public void printB() {
try {
System.out.println("线程名称是:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printB");
System.out.println("线程名称是:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printB");
} catch (Exception e) {
e.printStackTrace();
}
}
synchronized public static void printC() {
try {
System.out.println("线程名称是:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printC");
System.out.println("线程名称是:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printC");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ThreadA extends Thread{
private Service service;
public ThreadA(Service service){
super();
this.service = service;
}
@Override
public void run(){
super.run();
service.printA();
}
}
public class ThreadB extends Thread{
private Service service;
public ThreadB(Service service){
super();
this.service = service;
}
@Override
public void run(){
super.run();
service.printB();
}
}
public class ThreadC extends Thread{
private Service service;
public ThreadC(Service service){
super();
this.service = service;
}
@Override
public void run(){
super.run();
service.printC();
}
}
public static void main(String[] args) {
Service service = new Service();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB B = new ThreadB(service);
B.setName("B");
B.start();
ThreadC C = new ThreadC(service);
C.setName("C");
C.start();
}
}
- 运行结果:
线程名称是:A在1542965458417进入printA
线程名称是:B在1542965458418进入printB
线程名称是:B在1542965458418离开printB
线程名称是:A在1542965461417离开printA
线程名称是:C在1542965461417进入printC
线程名称是:C在1542965461418离开printC
可以看到加了static的printA()和printC()方法是同步的,而没有加static的printB()方法是异步的。所以得出加了static和synchronize关键字的锁是锁的class对象,而没加的则是是锁的实例对象。需要注意的是,当没有锁在方法上时,而是锁的方法里的同步块时,会产生异步。