CPU的运行,宏观上并行,微观上串行。
进程和线程之间的问题
一个进程是一个独立的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。java运行环境是一个包含了不同的类和程序的单一进程。线程可以被称为轻量级进程。线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源。多线程编程的好处是什么?
在多线程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲的状态。多个线程共享堆内存,因此创建多个线程去执行一些任务会比创建多个进程更好。例如在下载文件的时候,多个线程的下载是共享下载的资源的,所以多个线程的下载可以更快。
如何在java中运用多线程
对某一资源的共同使用和修改
对于资源的使用,有可能会出现同一时间内对对象的使用,造成错误的发生。例如下面的代码
public class Test02 {
public static void main(String[] args) {
Run1 run = new Run1();
Thread th = new Thread(run);
Thread th1 = new Thread(run);
Thread th2 = new Thread(run);
th.start();
th1.start();
th2.start();
}
}
class Run1 implements Runnable{
private int i =100;
@Override
public void run() {
// TODO Auto-generated method stub
while(i>0){
System.out.println(Thread.currentThread().getName()+" "+i);
i--;
}
}
}
class Run1 继承了 Runnable,并且通过通过多个线程共享一个类的地址使用,造成了有可能同一时间对同一个对象的重复调用。资源会有可能出现错误。
在这个时候需要在某段代码中使用锁,来确保这段代码只能某个线程去访问。synchronized()这个很好的复合的代码的保护。
public class Test02 {
public static void main(String[] args) {
Run1 run = new Run1();
Thread th = new Thread(run);
Thread th1 = new Thread(run);
Thread th2 = new Thread(run);
th.start();
th1.start();
th2.start();
}
}
class Run1 implements Runnable{
private int i =10000;
private Object one=new Object();
private Boolean changed = true;
@Override
public void run() {
// TODO Auto-generated method stub
while(changed){
if(i!=1){
synchronized (one) {
System.out.println(Thread.currentThread().getName()+" "+i--);
}
}else changed=false;
}
}
}
在上面的代码中有什么区别呢?首先多了个synchronized(),和Object对象,Object是任何的父类。synchronized()中需要绑定随意一个类来进行对象代码锁的操作。
在JDK1.5以后多了个Clone接口,这个是可以进行锁的操作。 使用方法 Lock lock = new ReetrantLock(); Condition con = lock.newConition(); Condition是可以从用一个Lock中多个定义。 方法con.await() con.signal();
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
在进行某些操作的时候,因为对数据操作先后顺序交互的需求,所以可以让某一先开始的线程等待后面进来的线程先完成,然后才唤醒该线程。这涉及线程的通信问题。
互斥,同步,死锁
- __互斥__当该资源为唯一的时候,那么就回有优先使用该资源的问题存在,那么就可以加锁。只能让某一线程使用该资源。
- __同步__当线程进行通信的时候,有可能需要使用到线程的同步,控制线程的先后顺序。先生产后消费。
- 死锁 通常死锁的问题是程序推进顺序不当导致的。就好像有个程序需要消费后才能生产,但生产又需要消费后才能生产。导致死锁。