java多线程学习一

多线程基础

  • 特点:代码的运行结果与代码的执行顺序是无关的。因为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对象,而没加的则是是锁的实例对象。需要注意的是,当没有锁在方法上时,而是锁的方法里的同步块时,会产生异步。

猜你喜欢

转载自blog.csdn.net/qq_39837953/article/details/84440068