java线程3种方法 以及线程安全

3种方法

  • callable的区别在于可以通过get获取返回值

继承Thread类

  • new Thread().start(); 如果直接new Thread,则没有指定start去运行什么
  • 因此才需要去继承,实现run方法
 new MyTreahd().start();
 //1.继承Thread类,重写该类的run()方法
 class MyTreahd extends Thread{
      @Override
      public void run() {
          super.run();
          Log.d(TAG,"MyTreahd extends Thread");
      }
  }

实现Runnalbe接口

  • Runnable中有run方法,但是没有start方法
 new Thread(new MyThread1(),"runnable thread").start();
 /*
  1.r.run()并不是启动线程,而是简单的方法调用。
  2.Thread也有run()方法,如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
  3.并不是一启动线程(调用start()方法)就执行这个线程,而是进入就绪状态,什么时候运行要看CUP。
  */
  class MyThread1 implements Runnable{
      @Override
      public void run() {
          Log.d(TAG,"MyTreahd1 implements Runnable");
      }
  }
  • 便捷写法
 new Thread(new Runnable() {
     @Override
      public void run() {
         ...
      }
  }).start();

通过 Callable 和 Future 创建线程

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。

  2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。

  3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。

  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

import java.util.concurrent.*;


class CallableThreadTest implements Callable<Integer> {
   

	@Override
	public Integer call() throws Exception {
		int i = 0;  
        for(;i<100;i++)  
        {  
            System.out.println(Thread.currentThread().getName()+" "+i);  
        }  
        return i;  
	}
}

class BaseThradTest{

	public static void main(String argv[]){
		System.out.println("...BaseThradTest...");
		CallableThreadTest ctt = new CallableThreadTest();
   		FutureTask<Integer> ft = new FutureTask<>(ctt);

		for(int i = 0;i < 100;i++)  
	        {  
	            System.out.println(Thread.currentThread().getName()+" 111"+i);  
	            if(i==20)  
	            {  
	                new Thread(ft,"11341").start();  
	            }  
	        }  
	        try  
	        {  
	            System.out.println("son "+ft.get());  
	        } catch (InterruptedException e)  
	        {  
	            e.printStackTrace();  
	        } catch (ExecutionException e)  
	        {  
	            e.printStackTrace();  
	        }  
	}

}

线程安全

线程中需要注意的

  • 是cpu的计算速度快还是cpu或者缓存,计算只需要处理。

  • volatile修饰:

    • 1、使用此关键字强制将修改的值立即写入内存
    • 2、使用volatile关键字的话,当线程2进行修改是,会导致线程1的工作内存中缓存变量stop的缓存行无效(反映到硬件的话,就是cpu的L1或者L2缓存中对应的缓存行无效)
    • 3、由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主存读取

    那么线程1读取到的就是最新的正确的值

  • synchronized

    • 1、静态同步方法, 对所有实例都是共享
    • 2、非静态同步方法,它是对this对象加锁,当前对象
    • 3、同步代码块,设置同步代码块的时候,里面的代码越少越好,锁粒度越细越好
      (由于int是基本数据类型,所以这里不能用int作为synchronize同步对象)
      (如果用this那么就类似前面的非对象同步,最好是采用类对象.)
  • 可重入锁 ReentrantLock

    • == 不需要再竞争
    • ReentrantLock是唯一实现了Lock接口的类
    • mlock.lock();//获取锁,如果无法获取锁,则处于等待状态
      mlock.lockInterruptibly();//允许当前线程被中断
      mlock.tryLock();//以非阻塞方式获取,可以立即返回,尝试获取,
      mlock.unlock();

synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动unLock释放,则会死锁,因此使用finally块中释放锁

CountDownLatch可以让线程同步执行

volatile例子

volatile例如 存在异常的例子
public class VolatileDemo{
	private static boolean stop = false;
	public static void main(){
		new Thread(new Runnable(){
			int i = 0;
			public void run(){
				while(!stop){
					System.out.println("正在运行");
				}
				System.out.priintln("结束运行");
			}
		}).start();
		stop = true;  // 则存在在cpu0中已经是true,而cpu1中stop一直是flase情况,那么这里的stop应该定义为volatile
	}
}

synchronized例子

synchronized例子
public class Syschronizedmet {

    private static int mvalue = 0;
    private Student mkl = new Student();
    private String mlk = new String();

    public static void main(String argv[]){
        Syschronizedmet msyn = new Syschronizedmet();
        /*
        *  下面两个线程对于methodA来说msyn是同一把锁,会出现阻塞,互斥
        * */
        /*
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodA();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodA();
            }
        }).start();
        */
        /*
        * 下面的方法锁不同,则不会互斥
        * */
        /*
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodA();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                new Syschronizedmet().methodA();
            }
        }).start();
        */
        /*
        *  不能同步执行
        * */
        /*
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodA();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodB();
            }
        }).start();
        */
        /*
        * 会互斥
        * */
        /*
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodB();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                new Syschronizedmet().methodB();
            }
        }).start();
        */
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodC();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                msyn.methodC();
            }
        }).start();
    }

    /*
    * 非静态同步
    *
    * 它是对this对象加锁,当前对象
     */
    public synchronized void methodA(){
        for(int i = 0; i < 100; i++)
            System.out.println("methodA:"+ i +" mvalue:"+mvalue++);
    }
    /*
    * 静态同步, 对所有实例都是共享。
    * */
    public static synchronized void methodB(){
        for(int i = 0; i < 100; i++)
            System.out.println("methodB:" +i+"  mvalue:"+mvalue++);
    }

    public void methodC(){
        //设置同步代码块的时候,里面的代码越少越好,锁粒度越细越好
        // 由于int是基本数据类型,所以这里不能用int作为synchronize同步对象
        //如果用this那么就类似前面的非对象同步,最好是采用类对象.
        synchronized (mlk){
            for(int i = 0; i < 100; i++)
                System.out.println("methodB:" +i+"  mvalue:"+mvalue++);
        }
    }

}

Lockdemo lock死等–(存在错误)

 private static CountDownLatch cdl = new CountDownLatch(2);

    public static void main(String argv[]){
        System.out.println("Lockdemo");
        Lockdemo mLockdemo = new Lockdemo();
        for(int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        cdl.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        mLockdemo.mm(Thread.currentThread());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            cdl.countDown();//-1
        }
    }
 public void mm(Thread thread) throws Exception{
        Lock mlock = new ReentrantLock();
        mlock.lock();
        try {
            System.out.println(thread.getName() + "获取锁成功");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            System.out.println(thread.getName() + "--> 释放锁");
        }
    }

Lockdemo
Thread-0获取锁成功
Thread-1获取锁成功
Thread-0--> 释放锁
Thread-1--> 释放锁
  • 上面的 错误 在于,在mm中去new的锁,两个线程持有的锁不一样,并且都未释放锁。
    修改
Lock mlock = new ReentrantLock();
mm(){
 	mlock.lock();
    try {
        System.out.println(thread.getName() + "获取锁成功");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        System.out.println(thread.getName() + "--> 释放锁");
        mlock.unlock();
    }
 }

Lockdemo tryLock – 锁获取不成功直接返回

 public void mm(Thread thread) throws Exception{
        if(mlock.tryLock()) {
            //mlock.lock();
            try {
                System.out.println(thread.getName() + "获取锁成功");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println(thread.getName() + "--> 释放锁");
                mlock.unlock();
            }
        }else{
            System.out.println("获取锁失败");
        }
    }

Lockdemo – lockInterruptibly

猜你喜欢

转载自blog.csdn.net/LHshooter/article/details/84845478
今日推荐