项目中的多线程并发以及字符串的常用方法

程序、进程、线程之间的关系

程序:一段静态的代码,静态的对象。

进程:程序的一次执行过程,正在运行的程序。如:运行中的QQ、运行中的MP3就是分别的两个进程。程序是静态的,进程是动态的。

线程:进程可以细划分为线程。是一个程序内部的一条执行路径。

如果一个程序在同一个时间执行了多个任务,那么就说这个程序是支持多线程的。

如:操作系统下可以运行多个进程,每个进程下可以执行多个线程。

什么时候使用到多线程

1)程序需要在同一时间执行两个和多个任务的时候

2)程序需要在执行的时候有一些等待的任务;如用户的输入、搜索、文件的读写操作、网络的操作等。

3)需要一些后台运行的程序时。

创建线程的三种方式:

扫描二维码关注公众号,回复: 1109105 查看本文章

public class TraditionalThread {
/**
* 创建线程的三种方式
*/
public static void main(String[] args) {

Thread thread = new Thread(){
// 使用匿名内部类创建线程
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1:" + Thread.currentThread().getName());

}
}
};
thread.start();

// 实现 Runnable
Thread thread2 = new Thread(new Runnable(){
@Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1:" + Thread.currentThread().getName());
}

}
});
thread2.start();
 /**
 * 实现Callable
 */
   int taskSize = 5;  
   // 创建一个线程池  
  ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
   // 创建多个有返回值的任务  
  List<Future> list = new ArrayList<Future>();  
  Vector vector=new Vector();
  List<String> list1=new ArrayList<String>();
  list1.add("from capture where id in(1,2)");
  list1.add("from capture where id in(3,4)");
  list1.add("from capture where id in(5,6)");
  list1.add("from capture where id in(7,8)");
  list1.add("from capture where id in(9,10)");
  for (String s:list1) {  
     Callable c = new MyCallable(s, vector);  
   // 执行任务并获取Future对象  
  Future f =  pool.submit(c);  
     list.add(f);  
  }  
  // 关闭线程池  
  pool.shutdown();  
  // 获取所有并发任务的运行结果  
  System.out.println(vector);
}
}

class MyCallable implements Callable<Object> {  
private String  sql; 
private Vector vector;
    MyCallable(String  sql,Vector vector) {  
  this.sql = sql; 
  this.vector=vector;
}  
  public Object call() throws Exception {  
//       System.out.println(">>>" + taskNum + "任务启动");
 vector.add(sql);
  return vector;  
    }
}  

窗口售票的案例:

1)继承Thread类的方式:

/**
 * 三个窗口共同出售100张票  为了保证ticket100 被三个实例共用 需要声明为static
 * 否则每个线程都会有着自己的实例 也就是说每个实例都有着ticket=100属性。
 * 即:各自有着100张票 这是不合理的。
 */
public class TestWindow {
    public static void main(String[] args) {
        Window window1 = new Window();
        Window window2 = new Window();
        Window window3 = new Window();
        window1.setName("窗口1: ");
        window2.setName("窗口2: ");
        window3.setName("窗口3: ");
        window1.start();
        window2.start();
        window3.start();
    }
}
class Window extends Thread {
   static  int ticket = 100;
    public void run() {
        while (true) {
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "售票,票号为" +ticket--);
            }else{
                break;
            }
        }
    }
}
2)实现Runnable接口的方式

/**
 * 创建线程的方式二
 * 实现Runnable接口的方式创建线程
 */
public class MyRunnable {
    public static void main(String[] args) {
        Window window = new Window();
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);
        Thread thread3 = new Thread(window);
        thread1.setName("窗口1:");
        thread2.setName("窗口2:");
        thread3.setName("窗口3:");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class Window implements Runnable {
    int ticket = 10;

    public void run() {
        while (true) {
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "售票,票号为" + ticket--);
            } else {
                break;
            }
        }
    }
}

3)实现Callable接口的方式

详细介绍Callable

而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。

Callable接口代表一段可以调用并返回结果的代码;Future接口表示异步任务,是还没有完成的任务给出的未来结果。所以说Callable用于产生结果,Future用于获取结果。

Callable接口使用泛型去定义它的返回类型。Executors类提供了一些有用的方法在线程池中执行Callable内的任务。由于Callable任务是并行的(并行就是整体看上去是并行的,其实在某个时间点只有一个线程在执行),我们必须等待它返回的结果。 

java.util.concurrent.Future对象为我们解决了这个问题。在线程池提交Callable任务后返回了一个Future对象,使用它可以知道Callable任务的状态和得到Callable返回的执行结果。Future提供了get()方法让我们可以等待Callable结束并获取它的执行结果。

那么怎么使用Callable呢?

ExecutorService

一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

第一个submit方法里面的参数类型就是Callable。

暂时只需要知道Callable一般是和ExecutorService配合来使用的,具体的使用方法讲在后面讲述。

一般情况下我们使用第一个submit方法和第三个submit方法,第二个submit方法很少使用。

Future

  Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

  Future类位于java.util.concurrent包下,它是一个接口:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

在Future接口中声明了5个方法,下面依次解释每个方法的作用:

cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。

isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。

isDone方法表示任务是否已经完成,若任务完成,则返回true;

get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;

get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

也就是说Future提供了三种功能:

  1)判断任务是否完成;

  2)能够中断任务;

  3)能够获取任务执行结果。

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

FutureTask

FutureTask实现了RunnableFuture接口,这个接口的定义如下:

public interface RunnableFuture<V> extends Runnable, Future<V> {  
    void run();  
}  

可以看到这个接口实现了Runnable和Future接口,接口中的具体实现由FutureTask来实现。这个类的两个构造方法如下 :

public FutureTask(Callable<V> callable) {  
        if (callable == null)  
            throw new NullPointerException();  
        sync = new Sync(callable);  
    }  
    public FutureTask(Runnable runnable, V result) {  
        sync = new Sync(Executors.callable(runnable, result));  
    }  

如上提供了两个构造函数,一个以Callable为参数,另外一个以Runnable为参数。这些类之间的关联对于任务建模的办法非常灵活,允许你基于FutureTask的Runnable特性(因为它实现了Runnable接口),把任务写成Callable,然后封装进一个由执行者调度并在必要时可以取消的FutureTask。

FutureTask可以由执行者调度,这一点很关键。它对外提供的方法基本上就是Future和Runnable接口的组合:get()、cancel、isDone()、isCancelled()和run(),而run()方法通常都是由执行者调用,我们基本上不需要直接调用它。

一个FutureTask的例子

/**
 * 创建线程的方式三
 * 实现Callable接口方式 然后重写call()方法
 * 1)此方式和Runnable类似 ; 但是Runnable不会返回结果,并且无法抛出返回结果的异常
 * 而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值,
 * 2)下面的应用通过ExecutorService的submit方法执行Callable
 * 3)FutureTask实现了两个接口,Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值,
 */

public class MyCallAble {
    public static void main(String[] args) {
        int taskSize = 5;
        // 创建一个线程池并返回ExecutorService实例
        ExecutorService executor = Executors.newFixedThreadPool(taskSize);
        SelfCallable callable1 = new SelfCallable(1000);                       // 要执行的任务
        SelfCallable callable2 = new SelfCallable(2000);
        FutureTask<String> futureTask1 = new FutureTask<String>(callable1);// 将Callable写的任务封装到一个由执行者调度的FutureTask对象
        FutureTask<String> futureTask2 = new FutureTask<String>(callable2);
        executor.submit(futureTask1);  // 执行任务 等同于 Future future1= executor.submit(callable1);
        executor.submit(futureTask2);//Future future2= executor.submit(callable2);
        try {
            System.out.println(futureTask1.get());//通过future获取返回值  future1.get()
            System.out.println(futureTask2.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class SelfCallable implements Callable<String> {
    private long waitTime;

    public SelfCallable(int times) {
        this.waitTime = times;
    }

    public String call() {
        try {
            Thread.sleep(waitTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Thread.currentThread().getName() + "  Test";
    }
}

总结:

线程中的常用方法

start():启动线程;并执行相应的run方法。

run():子线程要执行的代码存放在run()方法中。

currentThread():获取当前的线程。

getName():获取当前线程的名字。

setName():设置当前线程的name。

yield():调用此方法的线程会释放当前CPU的执行权。

join():方法可以使得一个线程在另一个线程结束后再执行。如果join()方法在一个线程实例上调用,当前运行着的线程将阻塞直到这个线程实例完成了执行。

isAlive():判断当前的线程是否存活。

sleep(long l):让当前的线程睡眠l毫秒。

interrupt():打断其睡眠阻塞。

以下的三个方法都是对象的方法

wait():让当前的线程挂起并放弃CPU、同步资源、使别的线程可以访问并修改共享的资源,而当前的线程只能排队等候再次对资源的访问。会释放对象的锁让别的线程使用同步资源。

notify():唤醒正在排队等候的同步资源线程优先级最高者结束等待。

notifyAll():唤醒正在排队等候的同步资源所有线程结束等待。

Object提供的这三个方法只能在Synchronized方法和Synchronized代码块使用,否则会报异常。

比较创建线程三种方式的区别

1)避免了Java单继承的局限性。

2)如果多个线程操作同一份资源(数据)更适合使用实现Runnable接口的方式。

3)Callable优于Thread和Runnable的地方就是 可以获取到返回值。


定时器

public class TraditionalTimerTest {
private static int count = 0;
public static void main(String[] args) {
new Timer().schedule(new TimerTask() {

 

@Override
public void run() {

         System.out.println("bombing!");

}
}, 10000);
}}每隔10s打印bombing

其中Timer为定时器,而TimerTask为任务。
线程的同步互斥(线程安全问题)
当多个线程访问同一个对象的时候就会出现线程安全问题。(如银行的存款和取款)
使用synchronized关键字 来修饰一个方法或者一个代码块,来保证在同一个时刻最多只有一个线程来执行代代码。
方式一:
同步代码块
synchronized(同步监视器){
//需要被同步的代码块(即为操作共享数据的代码)
}
1、共享数据:多个线程共同操作的同一数据(变量)
2、同步监视器:由一个类的对象充当,那个线程获取此监视器,谁就执行大括号里被同步的代码。俗称"锁"  Note:所有的线程必须共用一把锁
任何对象都能作为同步监视器,但是只能是类的全局变量,不能是局部变量。
在实现的方式创建线程可以使用this作为同步监视器,使用继承的方式创建线程不能使用this作为同步监视器。
可以使用this 即:当前的对象作为同步监视器。
/**
 * 创建线程的方式二
 * 实现Runnable接口的方式创建线程
 */
public class MyRunnable {
    public static void main(String[] args) {
        Window window = new Window();
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);
        Thread thread3 = new Thread(window);
        thread1.setName("窗口1:");
        thread2.setName("窗口2:");
        thread3.setName("窗口3:");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class Window implements Runnable {
    int ticket = 10;
    Object obj = new Object();

    public void run() {
     //Animal animal=new Animal();//局部变量
        while (true) {
            synchronized (obj) {// 使用this替换obj 表示执行此方法的当前对象  不能使用animal局部变量作为同步监视器。
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "售票,票号为" + ticket--);
                }
            }
        }
    }
}
方式二:
同步方法
操作共享数据的方法声明为synchronized。即为同步方法,能够保证当其中一个线程执行此方法的时候,其他线程在此方法外进行等待直至此线程执行完毕。
同步方法也有锁机制:同步方法的锁就是this。
/**
 * 创建线程的方式二
 * 实现Runnable接口的方式创建线程
 */
public class MyRunnable {
    public static void main(String[] args) {
        Window window = new Window();
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);
        Thread thread3 = new Thread(window);
        thread1.setName("窗口1:");
        thread2.setName("窗口2:");
        thread3.setName("窗口3:");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class Window implements Runnable {
    int ticket = 10;
    Object obj = new Object();
    public void run() {
        while (true) {
//            synchronized (obj) {// 使用this替换obj 表示执行此方法的当前对象
//                if (ticket > 0) {
//                    System.out.println(Thread.currentThread().getName() + "售票,票号为" + ticket--);
//                }
//            }
            show();//同步方法
        }
    }
    public  synchronized void show(){
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "售票,票号为" + ticket--);
        }
    }
}

案例:
两个储户分别向这个账户中存3000 一次存储1000 存3次 每次存储完打余额。
/**
 * 银行有一个账户
 * 两个储户分别向这个账户中存3000 一次存储1000 存3次 每次存储完打余额。
 * 1、是否需要多线程  两个储户
 * 2、是否有共享数据  同一个账户
 * 3、是否考虑线程的同步
 */
public class TestAccount {
    public static void main(String[] args) {
        Account account = new Account();
        Customer customer1 = new Customer(account);
        Customer customer2 = new Customer(account);
        Thread t1=new Thread(customer1);
        Thread t2=new Thread(customer2);
        t1.setName("储户1:");
        t2.setName("储户2:");
        t1.start();
        t2.start();
    }
}

class Customer implements Runnable {
    Account account;

    public Customer(Account account) {
        this.account = account;
    }

    public void run() {
        for (int i = 0; i < 3; i++) {
            account.deposit(1000);
        }
    }
}
class Account {
    double balance;//余额

    public Account() {

    }
    public synchronized  void deposit(double amt) {
        this.balance += amt;
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":" + balance);
    }

线程的中断

Thread.interrupt():中断睡眠阻塞。
public static void main(String[] args) {
/**
* 林永健,处于睡眠阻塞的线程
*/
final Thread lin=new Thread(new Runnable(){
public void run(){
System.out.println("林:刚美完容,睡觉去了!");
try{
Thread.sleep(1000000);//此线程进入睡眠阻塞
}catch(InterruptedException  e){
System.out.println("林:干嘛呢,干嘛呢!都破相了!");

}
}
});

/**
* 黄宏线程,用于中断林永健睡眠阻塞
*/
Thread huanghong=new Thread(new Runnable(){
public void run(){
System.out.println("开始砸墙!");
for(int i=0;i<5;i++){
System.out.println("黄:80!");
try{Thread.sleep(1000);
}catch(InterruptedException e){
}
}
System.out.println("咣当!");
System.out.println("黄:搞定!");

/**
* 一个方法的局部内部类中若要引用该方法的其他局部变量
* 那么这个变量必须是final的

*/
lin.interrupt();//中断林永健线程,打断其睡眠阻塞
}
});
lin.start();
huanghong.start();
}
}

线程的死锁


1)死锁的问题:处理线程同步时容易出现。
2)不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
3)写代码时,要避免死锁!

public class TestDeadLock {
    static StringBuffer sb1 = new StringBuffer();
    static StringBuffer sb2 = new StringBuffer();
    public static void main(String[] args) {
        new Thread() {
            public void run() {
                synchronized (sb1) {
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    sb1.append("A");
                    synchronized (sb2) {
                        sb2.append("B");
                        System.out.println(sb1);
                        System.out.println(sb2);
                    }
                }
            }
        }.start();

        new Thread() {
            public void run() {
                synchronized (sb2) {
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    sb1.append("C");
                    synchronized (sb1) {
                        sb2.append("D");
                        System.out.println(sb1);
                        System.out.println(sb2);
                    }
                }
            }
        }.start();
    }
}


线程通信

notify():唤醒正在排队等候的同步资源线程优先级最高者结束等待。

notifyAll():唤醒正在排队等候的同步资源所有线程结束等待。

Object提供的这三个方法只能在Synchronized方法和Synchronized代码块使用,否则会报异常。

案例:使用两个线程打印1-100 线程1、线程2交替打印。

//线程通信。如下的三个关键字使用的话,都得在同步代码块或同步方法中。
//wait():一旦一个线程执行到wait(),就释放当前的锁。
//notify()/notifyAll():唤醒wait的一个或所有的线程
//使用两个线程打印 1-100. 线程1, 线程2 交替打印
class PrintNum implements Runnable {
    int num = 1;
    Object obj = new Object();
    public void run() {
        while (true) {
            synchronized (obj) {
                obj.notify();//第二个线程握住锁后  唤醒第一个线程 
                if (num <= 100) {
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":"
                            + num);
                    num++;
                } else {
                    break;
                }
                try {
                    obj.wait();//释放锁 让另一个线程执行
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}
public class TestCommunication {
    public static void main(String[] args) {
        PrintNum p = new PrintNum();
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(p);

        t1.setName("甲");
        t2.setName("乙");

        t1.start();
        t2.start();
    }


线程的生命周期
现成生命周期的5中状态
新建状态 :Thread thread=new Thread();
就绪状态 :线程已经被启动(start),但是等着cpu分配时间片段。
运行状态: 线程获得了cpu的资源。
堵塞状态: 由于某种原因导致正在运行的线程让出了cpu并暂停了自己的执行。
死亡状态 :线程执行完毕或者被其他的线程杀死。
守护线程
java的垃圾回收就是一个守护线程
某个线程对象调用setDaemon(true)那么这个线程就是守护线程。守护线程必须在线程启动的时候执行。
/**
 * 后台线程与前台线程
 * @author Administrator
 *
 */
public class ThreadDemo3 {
public static void main(String[] args) {
Thread rose=new Thread(new Runnable(){
public void run(){
for(int i=0;i<10;i++){
System.out.println("rose:Let me go !");
try{ Thread.sleep(1000);
}catch(InterruptedException e){
}
}
System.out.println("rose:AAAAAaaaaa....");
System.out.println("噗通!");
}
});
Thread jack=new Thread(new Runnable(){
public void run(){
while(true){
System.out.println("jack:you jump! I jump!");
try{
Thread.sleep(1000);

}catch(InterruptedException e){

}
}
}
});
/**
* 设置后台线程的方法必须在该线程启动前调用
*/
jack.setDaemon(true);
jack.start();
rose.start();
System.out.println("main方法执行结束了");
}
}
线程中的sleep和notify方法

/**
 * Wait()  notify()方法
 * @author Administrator
 *
 */
public class WaiAndNotifyDemo {

public static boolean finish=false;

public static void main(String[] args) {
/**
* 两个线程并发运行
* 一个线程用于下载图片
* 另一个线程用于显示图片
* 这里就出现了一个问题,显示图片的线程应当等待下载图片的
* 线程将图片下载后再进行显示。
*/

String ids="1,2,3,4,5,6,7,8,9,10";
String[] split=ids.split(",");
List list=new ArrayList();
for(String str:split){

list.add(str);
}
List<String> result = new ArrayList<String>();
String temp=null;
for (int i = 0; i < list.size(); i++) {
if(i%2==0){
temp=list.get(i)+",";
}
if (i%2!=0) {
temp+=list.get(i);
result.add(temp);
temp=null;
}
}
for(String t:result){
System.out.println(t);
}
//下载图片的线程
final Thread downLoadThread =new Thread(new Runnable(){
public void run(){
System.out.println("开始下载图片。。。");
try{
Thread.sleep(5000);

}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("下载图片完毕");
finish=true;
/**
* 通知在当前对象上等待的线程回到runnable状态
* 这里的this就是downLoadThread
* 而下面的displayThread 就是在当前对象上等待的
* 所以调用this.notify()方法会调用displayThread
* 解除等待阻塞,使其可以继续进行
*/
synchronized(this){
this.notify();
}
}
});

//显示图片的线程
Thread displayThread =new Thread(new Runnable(){
public void run(){

try{
/**
* 当显示线程通过调用一个对象的wait方法后
* 那嘛这个线程就在当前线程上等待,进入阻塞
* wait 等待阻塞 与睡眠阻塞的区别在于:
* sleep()会在指定的时间消耗完毕后自动回到Runnable状态
* wait() 阻塞不会自动回到Runnable,直接调用了这个对象的notify
* ()方法,当前线程才会到runnable
*/
synchronized(downLoadThread){
/**
* 当前线程在哪个对象上等待,就需要获取那个对象的锁
*/
downLoadThread.wait();}
}catch(InterruptedException e){
e.printStackTrace();
}
// if(!finish){
//throw new RuntimeException("图片没有下载完成!");
//}
System.out.println("开始显示图片!");
}
});

displayThread.start();
downLoadThread.start();
}
}

需求:从浏览器中发送请求:请求的参数为10个id的值,如何把这10个id分成5个线程进行查询

思路:

contoller ids 1,2,3,4,5,6,7,8,9,10(controller中的值是从url中传入的)
service:   

          1. ids/5     1,2 3,4 5,6 7,8 9,10

          2. hql from t where id in(1,2)

            hql from t where id in(3,4)
            hql from t where id in(5,6)
           hql from t where id in(7,8)
           hql from t where id in(9,10)
          3. 5个线程,1个线程传递一个hql,执行查询

基础知识:

java创建线程的三种方式:Callable,Runnable,Thread比较及用法

第一种方式:继承Thread类

GetName()方法返回调用该方法的线程的名字。

public class MyThread extends Thread{
int i=0;
 public  void run(){
 for(int i=0; i<100;i++){
System.out.println(getName()+" "+i);
}
 }
 public static void main(String[] args) {
Thread t1=new MyThread();
Thread t2=new MyThread();
t1.start();
t2.start();
}
}

第二种方法:实现Runnable接口

(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

(3)调用线程对象的start()方法来启动该线程。

  1. public class RunnableThreadTest implements Runnable  
  2. {  
  3.   
  4.     private int i;  
  5.     public void run()  
  6.     {  
  7.         for(i = 0;i <100;i++)  
  8.         {  
  9.             System.out.println(Thread.currentThread().getName()+" "+i);  
  10.         }  
  11.     }  
  12.     public static void main(String[] args)  
  13.     {  
  14.         for(int i = 0;i < 100;i++)  
  15.         {  
  16.             System.out.println(Thread.currentThread().getName()+" "+i);  
  17.             if(i==20)  
  18.             {  
  19.                 RunnableThreadTest rtt = new RunnableThreadTest();  
  20.                 new Thread(rtt,"新线程1").start();  
  21.                 new Thread(rtt,"新线程2").start();  
  22.             }  
  23.         }  
  24.       }  
  25.   
第三种方式:

通过Callable和Future创建线程

1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。

(2)创建线程池,创建有多个返回值的任务,也就是说把返回值的任务放到一个集合中即:集合的泛型为Future类型。

(3)创建接口实现类的对象,往往在创建的对象的过程中构造方法需要传入要操作的属性值

(4)执行任务并获得Future对象,此对象的获得是通过线程池对象调用submit方法获得的,把Future对象添加到集合中。

    如果创建多个返回值的任务:红色的部分是必不可少的。

(5)关闭线程池,Future对象调用f.get()方法获取任务的返回值。

    使用线程池时call方法的执行是在submit方法执行时开始执行。

@SuppressWarnings("unchecked")

public class CallableThreadTest{
public static void main(String[] args) throws ExecutionException,InterruptedException {  
   System.out.println("----程序开始运行----");  
  Date date1 = new Date();  
    int taskSize = 5;  
   // 创建一个线程池  
  ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
   // 创建多个有返回值的任务  
  List<Future> list = new ArrayList<Future>();  
  for (int i = 0; i < taskSize; i++) {  
        Callable c = new MyCallable(i+"");  
   // 执行任务并获取Future对象  
   Future f = pool.submit(c);  
     list.add(f);  
  }  
  // 关闭线程池  
  pool.shutdown();  
  // 获取所有并发任务的运行结果  
  for (Future f : list) {  
  // 从Future对象上获取任务的返回值,并输出到控制台  
   System.out.println(">>>" + f.get().toString());  
   }  
}
  }  
  class MyCallable implements Callable<Object> {  
private String   taskNum;  
     MyCallable(String  string) {  
   this.taskNum = string;  
}  
  public Object call() throws Exception {  
        System.out.println(">>>" + taskNum + "任务启动");  
  Date dateTmp1 = new Date();  
  Thread.sleep(1000);  
          Date dateTmp2 = new Date();  
  long time = dateTmp2.getTime() - dateTmp1.getTime();  
  System.out.println(">>>" + taskNum + "任务终止");  
   return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";  
}  
}  

书写的过程:

在main方法中或者service方法中定义线程池的大小,并且创建线程池;创建有多个返回值的任务;创建线程(创建的方式大同小异,往往都是通过增强for循环创建)for循环中的内容基本固定,唯一不同的是实现类的构造方法的内容,构造方法中的内容需要在类的属性中进行定义;

          int taskSize = 5;  
         // 1)创建一个线程池  
  ExecutorService pool = Executors.newFixedThreadPool(taskSize);  

        // 2)创建多个有返回值的任务  
  List<Future> list = new ArrayList<Future>();  

//3) 创建线程
 for (int i = 0; i < taskSize; i++) {  
        Callable c = new MyCallable(i+"");  
   // 执行任务并获取Future对象  
   Future f = pool.submit(c);  
     list.add(f);  
  }  

项目代码:

public List<CaptureLog> getFaceLogList(String ids,Integer currentPage,Integer pageSize, Long logStartTime, Long logEndTime,Integer timeType, String cameraIds, Integer gender, Integer minAge,Integer maxAge, Integer feature) {
String[] split = ids.split(",");
List<String> list = new ArrayList<String>();
for (String str1 : split) {
list.add(str1);
}
List<String> result = new ArrayList<String>();
String temp=null;
for (int i = 0; i < list.size(); i++) {
if(i%2==0){
temp=list.get(i)+",";
}
if (i%2!=0) {
temp+=list.get(i);
result.add(temp);
temp=null;
}
}
List<String> sqlList = new ArrayList<String>(result.size());
for(String str : result) {
String conditionResult = structureSearchCondition(str,logStartTime,logEndTime, timeType, cameraIds, gender, minAge, maxAge,feature,null);
sqlList.add("FROM CaptureLog"+conditionResult);
}
int taskSize=5;
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 创建多个有返回值的任务
List<Future> list1= new ArrayList<Future>();

     //将查询到的结果(集合)放到安全的集合中
Vector vector = new Vector();
//创建线程
for(String sql : sqlList) {
Callable c = new ThreadQuery(sql, vector);
Future f = pool.submit(c);
list1.add(f);
}
      return vector;
}

@SuppressWarnings("rawtypes")
class ThreadQuery implements Callable {
private Vector vector;
private String sql;
ThreadQuery(String sql, Vector vector) 
{
this.vector = vector;
this.sql = sql;
}
   @Override
public Object call() throws Exception {
Query query = entityManager.createQuery(sql);
List<CaptureLog> list=query.getResultList();
System.out.println(list);
vector.addAll(list);
return vector;
}
}

此线程的执行顺序:

main方法或者service方法--》从上到下开始执行当执行到submit方法时执行call方法的内容,再去执行main方法或sevice方法的内容。

带逗号的字符串从逗号分隔的情况:

String[] split = ids.split(",");
List<String> list = new ArrayList<String>();
for (String str1 : split) {
list.add(str1);
}
List<String> result = new ArrayList<String>();
String temp=null;
for (int i = 0; i < list.size(); i++) {
if(i%2==0){
temp=list.get(i)+",";
}
if (i%2!=0) {
temp+=list.get(i);
result.add(temp);
temp=null;

}



猜你喜欢

转载自blog.csdn.net/yangshaojun1992/article/details/50981217
今日推荐