zl程序教程

您现在的位置是:首页 >  后端

当前栏目

java多线程编程

2023-06-13 09:13:26 时间

在多线程编程下,对处理并发时,可能产生重复工作的线程,

首先,从基础的说起

第一步如何创建一个线程、运行一个线程

Tread thread = new Thread();
thread.start();

第二步,在线程里实现功能

这里大部分部分内容参考了http://ifeve.com/creating-and-starting-java-threads/

由于,线程启动之后会自动运行run()函数里的代码,所以需要实现功能有两种方式:

一种是创建Thread子类的一个实例并重写run方法

public class MyThread extends Thread {
   public void run(){
     System.out.println("MyThread running");
   }
}

可以用如下方式创建并运行上述Thread子类

MyThread myThread = new MyThread();
myTread.start();

创建匿名类的方式

Thread thread = new Thread(){
   public void run(){
     System.out.println("Thread Running");
   }
};
thread.start();

第二种是创建类的时候实现Runnable接口:

public class MyRunnable implements Runnable {
   public void run(){
    System.out.println("MyRunnable running");
   }
}

为了使线程能够执行run()方法,需要在Thread类的构造函数中传入 MyRunnable的实例对象。示例如下:

Thread thread = new Thread(new MyRunnable());
thread.start();

匿名类实现:

Runnable myRunnable = new Runnable(){
   public void run(){
     System.out.println("Runnable running");
   }
}
Thread thread = new Thread(myRunnable);
thread.start();

具体这两种的比较,网上有很多资料可以查,但有一点: 因为线程池可以有效的管理实现了Runnable接口的线程,如果线程池满了,新的线程就会排队等候执行,直到线程池空闲出来为止。而如果线程是通过实现Thread子类实现的,这将会复杂一些,有时需要两种方式都用。

常见错误:调用run()方法而非start()方法

创建并运行一个线程所犯的常见错误是调用线程的run()方法而非start()方法,如下所示:

Thread newThread = new Thread(MyRunnable());
newThread.run();  //should be start();

事实上,run()方法并非是由刚创建的新线程所执行的,而是被创建新线程的当前线程所执行了。也就是被执行上面两行代码的线程所执行的。想要让创建的新线程执行run()方法,必须调用新线程的start方法。

第三步,向线程中传递参数

一般来说,线程中处理的事务多数需要外界参数,这里有三种方法,具体参考

http://www.jb51.net/article/31981.htm

第四步,在多线程环境下,找到指定命名的当前运行的线程

第一点是给线程命名 当创建一个线程的时候,可以给线程起一个名字。它有助于我们区分不同的线程。例如:如果有多个线程写入System.out,我们就能够通过线程名容易的找出是哪个线程正在输出。例子如下:

MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable, "New Thread");
thread.start();
System.out.println(thread.getName());

需要注意的是,因为MyRunnable并非Thread的子类,所以MyRunnable类并没有getName()方法。可以通过以下方式得到当前线程的引用:

Thread.currentThread();

因此,通过如下代码可以得到当前线程的名字:

String threadName = Thread.currentThread().getName();

线程代码举例: 这里是一个小小的例子。首先输出执行main()方法线程名字。这个线程JVM分配的。然后开启10个线程,命名为1~10。每个线程输出自己的名字后就退出。

public class ThreadExample {
  public static void main(String[] args){
     System.out.println(Thread.currentThread().getName());
      for(int i=0; i<10; i++){
         new Thread("" + i){
            public void run(){
             System.out.println("Thread: " + getName() + "running");
            }
         }.start();
      }
  }
}

需要注意的是,尽管启动线程的顺序是有序的,但是执行的顺序并非是有序的。也就是说,1号线程并不一定是第一个将自己名字输出到控制台的线程。这是因为线程是并行执行而非顺序的。Jvm和操作系统一起决定了线程的执行顺序,他和线程的启动顺序并非一定是一致的。

第二点是找到对应名称的线程

在多线程编程中,处理并发情况下,很容易出现某一个线程的内容重复使用,如果线程使用率较高,或者某个线程具有延迟等功能的话,多次创建新的线程不利于线程管理,也容易造成阻塞,所以,在这些线程的过程中需要判断,当前运行的线程中是否有对应名字的线程

下面代码用于取得所有的正在运行线程的名字:

ThreadGroup group = Thread.currentThread().getThreadGroup();
ThreadGroup topGroup = group;
// 遍历线程组树,获取根线程组
while (group != null) {
	topGroup = group;
	group = group.getParent();
}
// 激活的线程数加倍
int estimatedSize = topGroup.activeCount() * 2;
Thread[] slackList = new Thread[estimatedSize];
// 获取根线程组的所有线程
int actualSize = topGroup.enumerate(slackList);
// copy into a list that is the exact size
Thread[] list = new Thread[actualSize];
System.arraycopy(slackList, 0, list, 0, actualSize);
System.out.println("Thread list size == " + list.length);
for (Thread thread : list) {
	System.out.println(thread.getName());    //这里取得名字后可以进行逻辑操作
}

这里其实有个问题,因为拿到的是所有线程,包括父线程,所以当同一时间运行程序很多的时候可能会拿到大量无用的线程,

在工程中可以建立一个静态列表,在创建某个线程的时候,把命名放在这个列表里面,然后在搜素的时候可以先查列表,如果只是知道某个线程在不在启动,则可以用这个简便算法

最后再次感谢

http://ifeve.com/creating-and-starting-java-threads/

http://www.jb51.net/article/31981.htm

http://trinityblood.iteye.com/blog/1618181

三位作者的大力支持