java多线程

来源:互联网 发布:mysql 5.5.37 for mac 编辑:程序博客网 时间:2024/06/07 12:15

线程的创建方式有两种

继承Thread类

public class ThreadTest extends Thread{public void run(){for(int i = 0;i < 10;i++)System.out.println(i);}public static void main(String[] args) {new ThreadTest().start();}}

重写run()即可。

Thread类有如下几个常用的方法:

public static void yield()  //暂停当前正在执行的线程对象,并执行其他线程
public static void sleep(long millis)  //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。
public void interrupt()  //中断线程
public static boolean interrupted()  //测试当前线程是否已经中断
public boolean isInterrupted()  //测试线程是否已经中断
public final boolean isAlive()  //测试线程是否处于活动状态 
public final void setPriority(int newPriority)  //更改线程的优先级
public final void setName(String name)  //改变线程名称,使之与参数 name 相同
public final void join()  //等待该线程终止
public final void setDaemon(boolean on)  //将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出
public void setContextClassLoader(ClassLoader cl)  //设置该线程的上下文 ClassLoader
public static void yield()  //暂停当前正在执行的线程对象,并执行其他线程

实现Runnable接口

public class RunnableTest implements Runnable{private int count;private int num;public RunnableTest(int i,int num){count  = i;this.num = num;}public void run(){for(int i = 0;i < count;i++)System.out.println("num"+num+":"+i);}public static void main(String[] args) {Runnable r1 = new RunnableTest(10,1);Runnable r2 = new RunnableTest(20,2);new Thread(r1).start();new Thread(r2).start();}}

创建两个任务,通过Thread类执行任务。

线程的创建需要一定的代价,所以当需要执行多个任务时,创建同样多的线程是不可取的。这时可以使用线程池创建一定数量的线程,同一个线程在执行完一个任务后可以去执行另外的任务,也就是线程的重复利用。如:

public static void main(String[] args) {/*Runnable r1 = new RunnableTest(10,1);Runnable r2 = new RunnableTest(20,2);new Thread(r1).start();new Thread(r2).start();*/ExecutorService es = Executors.newFixedThreadPool(10);for(int i = 0;i < 100;i++){es.execute(new RunnableTest(i*3,i));}es.shutdown();}

创建10个线程用于执行100个任务。

其中,Executors类提供了一些静态方法用于获取各种类型的线程池。相关信息可以查帮助文档。

线程同步

当多个线程需要访问相同的资源(如变量,java对象)时,就涉及到了线程之间的同步问题。在java中,线程同步使用synchronized关键字即可。当然,也可以通过Lock接口显示的加锁。

如果给一个实例方法(类方法)声明为synchronized,那么当一个线程访问这个方法时会隐式地给对象加锁,其他线程访问这个对象(类)的同步方法时就会被阻塞(访问非同步方法不会阻塞)。

如果是同步块,那么一个线程访问同步块所在的方法时,不会阻塞其他线程对其他同步方法,而只是阻塞所同步的对象的访问,即synchronized(Object o)里面的o对象。

如果是显示地加锁,那么先通过new ReentrantLock()获得一把锁,然后在需要同步的代码调用其lock()和unlock()即可。

另外,通过Lock接口的newCondition()获得一个Condition类,其中的await(),signal(),signelAll()可以实现线程间的协作。请看下面一个经典例子:

package multi_thread;import java.util.LinkedList;import java.util.Random;import java.util.Vector;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ProductorConsumerTest {private static Buffer buf = new Buffer(30);private static Random rand = new Random();public static void main(String[] args) {ExecutorService es = Executors.newFixedThreadPool(6);for(int i = 0;i < 3;i++){es.execute(new Product(i));}for(int i = 0;i < 3;i++){es.execute(new Consumer(i));}es.shutdown();}static class Product implements Runnable{private int num;public Product(int num){this.num = num;}public void run(){while(true){int i = rand.nextInt(15);//System.out.println("product "+num+":"+i);buf.setn(i);try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}static class Consumer implements Runnable{private int num;public Consumer(int num){this.num = num;}public void run(){while(true){int i = rand.nextInt(15);//System.out.println("consumer "+num+":"+i);buf.getn(i);try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}class Buffer{private static int count = 0;private LinkedList<Integer> buf = new LinkedList<Integer>();private int size = 0;private Lock lock = new ReentrantLock();private Condition empty = lock.newCondition();private Condition full = lock.newCondition();public Buffer(int size){this.size = size;}public void setn(int n){lock.lock();while(buf.size()+n > size){System.out.println("buf.size():"+buf.size()+";setn("+n+")...please wait");try {full.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int i = 0;i < n;i++){buf.add(count++);}System.out.println("buf.size():"+buf.size()+";setn("+n+")");empty.signal();lock.unlock();}public void getn(int n){lock.lock();while(buf.size()-n < 0){System.out.println("buf.size():"+buf.size()+";getn("+n+")...please wait");try {empty.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int i = 0;i < n;i++){buf.remove(0);}System.out.println("buf.size():"+buf.size()+";getn("+n+")");full.signal();lock.unlock();}}

用Lock和Condition完成生产者消费者的问题。


另外附上两个并发编程的例子吧。

i++

首先要说明的是,在java中i++操作不是原子操作,这就意味着如果i是多线程共享的,那么i++操作就不是线程安全的。

那么,可以使用java提供的原子类来解决问题。在java.util.concurrent.atomic包中有AtomicLong,AtomicInteger等类提供线程安全的操作。

不安全的单例类

public class Singleton {private static Singleton single = null;private Singleton(){}public static Singleton getInstance(){if(single == null){single = new Singleton();}return single;}}

当两个线程同时访问getInstance()时,可能一个线程判断single为null,然后执行new Singleton(),而同时另一个线程在它还没创建完成时也判断single是否为null,这是两个线程就都创建了一个Singleton实例了,显然这是不符合单例模式的初衷的。


0 0
原创粉丝点击