文章目录
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 创建线程
-
创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
-
创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
-
使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
-
调用 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("获取锁失败");
}
}