您的位置:首页 > 编程语言 > Java开发

Java多线程碎碎念

2016-01-04 12:25 375 查看
创建线程的几种方法

实现多线程的几种方式

线程之间同步
为什么要同步

同步有哪些策略
synchronized

Lock

线程的一些方法介绍和object的wait notify

创建线程的几种方法

“你知道茴字有几种写法吗?”孔乙己笑着说道.

“你知道创建线程有几种方法吗?”

继承Thread

------------MThread.java----------------
class MThread extends Thread
{
@Override
public void run()
{
//自己的代码逻辑
}
}
-------------main函数--------------------
Thread t = new MThread();
t.start();


实现Runnable

------------MRunnable.java----------------
class MRunnable implements Runnable
{

@Override
public void run()
{
//自己的代码逻辑
}
}
-------------main函数--------------------
Thread t = new Thread(new mRunnable());
t.start();


实现Callable接口,通过FuctureTask 类实现有返回值的线程

-----------------CallbackImpl-------------
class CallableImp implements Callable<Integer>
{
private boolean isInterrupt = false;
@Override
public Integer call() throws Exception
{
while (!isInterrupt)
{
System.out.println(" call call");
Thread.sleep(1000);
isInterrupt = true;
}
return new Integer(13);
}
}
---------------------main.java--------------------
CallableImp call = new CallableImp("AAA");
//FutureTask是Future接口的实现类,它的作用是获取Callable的返回值
FutureTask<Integer> task = new FutureTask<>(call);
Thread thread = new Thread(task);
thread.start();
//获取返回值,这个方法一直等待线程结束,然后把返回值返回
//另外还有一个重载的函数,提供了超时退出等待的时间参数
// get(long timeout, TimeUnit unit)
Integer res = task.get();
System.out.println(res);


实现多线程的几种方式

多线程很简单,new 多个线程就OK.简单直接,但是也很粗暴.这种方式不便于管理,而且线程的创建是需要很多资源的.我们自然而然想到,多线程的目的是为了获得计算能力,如果我们的线程使用完之后不会被释放,可以回收再利用,那该多方便

CallableImp call1 = new CallableImp("callable___1");
CallableImp call2 = new CallableImp("callable___2");
CallableImp call3 = new CallableImp("callable___3");
CallableImp call4 = new CallableImp("callable___4");

ExecutorService e = Executors.newFixedThreadPool(4);
e.submit(call1);
e.submit(call2);
e.submit(call3);
e.submit(call4);
Thread.sleep(5000);
//执行完毕之后关闭
//如果想粗暴的关闭
//使用shutdownNow()
e.shutdown();


Executors有几个静态函数用来构造各种线程池

submit就是把 Runnable Callable 添加到线程池中等待执行,其返回值是Future对象,同样用于获取将来的返回值

上面是线程池,Java 7 还有一个用于多核计算,分割大任务,多线程计算之后,再合并计算结果的框架 Fork/Join框架,下次再写 (其实是还没吃透 ~逃 )

线程之间同步

为什么要同步(java线程内存模型),也就是说多线程不同步回引发什么问题(银行取钱案例)

为什么要同步?



上图为Java 内存模型 对一个主存里面的对象操作其实是先把这个对象复制到本地内存然后读写之后更新到主存里面,这样就导致了如果线程调度打断了更新那么就会导致出现错误,所以需要同步,同步就是然某些操作只可能被一个线程执行,也就是虽不存在多个线程执行同一个操作

同步有哪些策略?

synchronized

synchronized可以修饰方法,也可以修饰块

//括号里的参数是你想获得的哪个对象的锁参数就是那个对象
synchronized(this)
{
//对某一个共享对象的操作
}

//同步方法是锁的目标是this
public synchronized void function()
{
}


释放锁的情况

同步块执行完毕

同步块遇到了wait()

不会释放的情况

遇到sleep,yeild

suspend挂起线程

明天再写,碎觉~

我来更新啦

Lock

因为synchronized是有局限性的,例如我们需要在多个线程里面对一个共享数据执行些操作和读操作,自然想到应该线程之间的读和写不能同时进行,写和写也不能,但是读和读之间应该是可以同时进行的.那么我们用synchronized应该怎么实现呢

-----------Data.java--------------
class Data
{
private String data = null;
public Data(String data)
{

this.data = data;
}
public synchronized  void setData(String newData)
{
System.out.println(this.getName()+"写入数据= " + newData);
try
{
Thread.sleep(10);
}catch(){
}
data = newData;
}

public synchronized String getData()
{
System.out.println(this.getName()+"读取数据= "+data);
try
{
Thread.sleep(10);
}catch(){
}
return data;
}

}

------------MThread.java-----------------
class MThread
{
private Data d= null;
public MThread(Data d)
{
this.d = d;
}

@Override
public void run()
{

String data = d.get();

d.setData(this.getName()+"设置数据");

}
}

-------------main--------------
Data d = new Data("默认数据");
new MThread(d).start();
new MThread(d).start();
new MThread(d).start();


我们发现读和读之间也变成互斥的了

这个时候如果采用Lock就会很方便的实现读与读之间的不互斥关系

-----------Data.java--------------
class Data
{
private ReadWriteLock lock = new ReentrantReadWriteLock();
private String data = null;
public Data(String data)
{

this.data = data;
}
public void setData(String newData)
{
lock.writeLock().lock();
try
{
System.out.println(this.getName()+"写入数据= " + newData);
try
{
Thread.sleep(10);
}catch(){}

data = newData;
}
finally{
lock.writeLock().unlock();
}
}

public String getData()
{
lock.readLock().lock();
try
{
System.out.println(this.getName()+"读取数据= "+data);
try
{
Thread.sleep(10);
}catch(){
}
return data;
}
finally
{
lock.readLock().unlock();
}
}

}


通过读写锁就可以很方便的控制互斥与费互斥,另外还有很多的Lock子类供我们使用,参见api

线程的一些方法介绍和object的wait notify

join

这个方法的作用是

-----当前在主线程MainThread中------
threadA.join();


作用就是主线程MainThread等待threadA线程执行完毕再往下执行

yield

这个方法是调用者的线程放弃占用CPU,也就是释放CPU,然后大家再一起竞争CPU的使用权. 这个方法不会释放锁

sleep

这个方法是释放CPU一段时间,但是注意这个方法不会释放锁

wait

这个方法是Object中的方法,它的作用是使得当前这个线程进入等待状态,一直等待下去(ps : 可以使用带参数的重载函数起设定一个超时等待期限),直到有其他线程调用了notify系列函数 这个方法释放锁

notify

这一系列的函数用来使得进入等待状态的线程重新正常工作
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程 线程