多线程笔记

多线程笔记

创建线程

1、通过Runnable创建线程

 

实现Runnable接口(它只有一个void run()方法),然后将此类实例对象传给Thread对象,再调用Thread对象的start()方法

class MyThread implements Runnable{

       …………..

       public void run(){

              …………..

       }

}

在客户端:

MyThread mt = new MyThread();

Thread thread = new Thread(mt);或者Thread thread = new Thread(mt,name);

thread.start();

其中thread.start()方法调用mtrun()方法

2、通过Thread创建线程

继承Thread,重写run()方法

class MyThread extends Thread{

       …………..

       public void run(){

              .........

       }

}

在客户端:

MyThread myThread = new MyThread();

myThread.start();

其中myThread.start()调用重写的run()方法。

 

线程同步

当一个对象或者方法被多个线程访问或者共享时,此对象或者方法就必须同步,当一个线程进入同步方法或者同步代码块中时,其他线程就无法访问共享资源了。

1)同步方法:

synchronized 返回类型 method(argList){

       //同步方法体

}

一个线程执行同步方法是时,就获得了对象的监视器,且对象会加锁,其他线程无法对此对象执行同步方法,除非该线程执行完毕或者调用了wait()方法释放锁。

2)同步代码块

synchronized(引用对象){

       //同步语句

}

一旦一个线程进入同步代码块,线程就获得锁,引用对象就会被锁住,其他线程无法执行该对象的方法,除非同步代码块执行结束。

 

线程间通信

当线程1执行同步代码快时,它需要访问其他资源,但是资源暂时无法访问,如果线程1一直等待资源,而它占有对象的锁,那么其他线程就会一直等待。一个好的方式是,让线程1进入等待状态,等到资源可用时,用另外一个线程唤醒它。

 

在同步方法或者同步代码块中调用wait()进入等待,让其他线程执行;

在同步方法或者同步代码块中调用notify()唤醒等待线程,让其继续执行;

注意:线程间通信都是在同一个线程中进行,且两个方法都是Object对象的。

class SynObj{

       private boolean ready = false;

       synchronized void waitFor(){

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

              System.out.println(thrdName+"进入waitFor()方法。");

              System.out.println(thrdName+"调用wait()方法,等待唤醒。");

 

              try{

                     while(!ready)wait();

                    

                     }catch(InterruptedException e){

                            System.out.println("线程中断");

                     }

              System.out.println(thrdName+"收到通知,恢复执行。");

 

 

       }

       synchronized void goHead(){

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

              System.out.println(thrdName+"进入goHead()方法,调用notify()方法唤醒MyThread");

              ready = true ;

              notify();

      

       }

}

class MyThread implements Runnable{

       SynObj synObj;

       public MyThread(String name,SynObj so){

              synObj = so;

              new Thread(this,name).start();

       }

       public void run(){

              synObj.waitFor();

       }

       public static void main(String[] args) {

              System.out.println("Hello World!");

       }

}

public class MainClass{

       public static void main(String[] args) {

              try{

                     SynObj so = new SynObj();

                     new MyThread("MyThread",so);

                     for(int i=0;i<50;i++){

                            Thread.sleep(500);

                            System.out.print(".");

                     }

                     System.out.println();

                     so.goHead();

              }catch(InterruptedException e){

                            System.out.println("主线程线程中断");

                     }

       }

}

 

线程暂停、恢复及停止

Java本身的suspend()resume()stop()方法可能导致死锁。我们可以通过两个boolean变量表示线程状态,根据值来决定是否暂停、等待、结束。

class MyThread2 implements Runnable{

       Thread thrd ;

       private volatile boolean suspended;//是否暂停线程

       private volatile boolean stopped;//是否停止线程

 

       public MyThread2(String name){

              thrd = new Thread(this,name);

              suspended= false;

              stopped = false ;

              thrd.start();

       }

       public void run(){

              System.out.println(thrd.getName()+" 启动。");

              try{

                     for(int i=0;i<1000;i++){

                            System.out.print(".");

                            Thread.sleep(400);

                            synchronized (this){

                                   while(suspended)wait();

                                   if(stopped)break;

                            }

                     }

              }catch(InterruptedException e){

                     System.out.println(thrd.getName()+"异常程线程中断");

              }

              System.out.println(thrd.getName()+"线程退出。");

       }

       synchronized void stopThread(){

              stopped = true ;

              suspended = false ;

              notify();

       }

       synchronized void suspendThread(){

              suspended = true ;

       }

       synchronized void resumeThread(){

              suspended = false ;

              notify();

       }

}

public class MainClass2{

       public static void main(String[] args) {

              MyThread2 mt = new MyThread2("MyThread2");

              try{

                     Thread.sleep(3000);//主线程睡眠

                     System.out.println("/n暂停MyThread2线程");

                     mt.suspendThread();

 

                     Thread.sleep(3000);//主线程睡眠

                     System.out.println("/n恢复MyThread2线程");

                     mt.resumeThread();

 

                     Thread.sleep(3000);//主线程睡眠

                     System.out.println("/n停止MyThread2线程");

                     mt.stopThread();

              }catch(InterruptedException e){

                            System.out.println("主线程线程中断");

                     }

       }

}

 

 

守护线程

Java中有用户线程和守护线程。守护线程一般运行在后台提供服务,直到程序结束,它会自动终止,不需要手工停止。

如果Thread实例是由守护线程创建的,那么此实例也是守护线程,如果是由用户线程创建的,那么就是用户线程,但是可以通过调用它的setDaemon()将它设置成守护线程。注意此方法必须在线程启动前调用才有效。可以通过isDaemon()查看线程是否为守护线程。

例子:通过守护线程实现行程提醒的功能

import java.util.*;

class Reminder implements Runnable{

       private Calendar reminderTime;//提醒时间

       private String message ;//提醒消息

 

       public Reminder(String msg,int delay){//delay:延迟的时间()

              message = msg;

              reminderTime = Calendar.getInstance();

              reminderTime.add(Calendar.SECOND,delay);

              System.out.println("设置提醒:"+ message);

 

              Thread thrd = new Thread(this);

              thrd.setDaemon(true);

              thrd.start();

       }

       public Reminder(String msg,Calendar cal){//delay:延迟的时间()

              message = msg;

              reminderTime = cal;

              System.out.println("设置提醒:"+ message);

 

 

              Thread thrd = new Thread(this);

              thrd.setDaemon(true);

              thrd.start();

       }

       public void run(){

             

              try{

                     for(;;){

                            Calendar curTime = Calendar.getInstance();

                            if(curTime.compareTo(reminderTime) >= 0){

                                   System.out.println("/n"+message+"/n");

                                   break ;

                            }

                     }

                     Thread.sleep(1000);

              }catch(InterruptedException e){

                     System.out.println("Reminder异常中断");

              }

             

             

       }

      

}

public class MainClass3{

       public static void main(String[] args) {

              Reminder mt = new Reminder("XX打电话",10);

              Reminder mt2 = new Reminder("XX见面",new GregorianCalendar(2011,5,20,10,39));

              for(int i =0;i<50;i++){

                     try{

                            Thread.sleep(1000);

                     }catch(InterruptedException e){

                            System.out.println("主线程异常中断");

                     }

                     System.out.print(".");

              }

              System.out.println("主线程执行完毕");

             

       }

}

 

 

 

线程中断

要中断一个线程,可以在另一个线程中调用那个线程的interrupt()方法;

 

一个例子:多线程下载

import java.io.*;

import java.net.*;

public class MulThreadDownload {

       public static void main(String[] args) {

              String path = "http://softdl1.tech.qq.com/soft/38/QQPinyin_Setup_43_1080.exe";//下载的文件地址

              try {

                     new MulThreadDownload().download(path, 3);

              } catch (Exception e) {

                     e.printStackTrace();

              }

       }

       //从路径中获取文件名称

       public static String getFilename(String path){

              return path.substring(path.lastIndexOf('/')+1);

       }

       //下载文件的方法;path:下载路径;threadsize:线程数

       public void download(String path, int threadsize) throws Exception{

              URL url = new URL(path);    //根据路径创建URL对象

              HttpURLConnection conn = (HttpURLConnection)url.openConnection();

              conn.setRequestMethod("GET");//GET

              conn.setConnectTimeout(10 * 1000);//连接超时时间

              int filelength = conn.getContentLength();//通过连接获取要下载的文件的长度

              String filename = getFilename(path);//从路径中获取文件名称

 

              File saveFile = new File(filename);//创建下载的文件(相对路径,文件名相同)

              RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rw");//可读写的随机访问文件

              accessFile.setLength(filelength);//设置本地文件的长度和下载文件相同

              accessFile.close();

              //计算每条线程下载的数据长度

              int block = filelength%threadsize==0? filelength/threadsize : filelength/threadsize+1;//每条线程下载的数据长度

              for(int threadid=0 ; threadid < threadsize ; threadid++){

                     new DownloadThread(url, saveFile, block, threadid).start();//启动各个线程

              }

              System.out.println( "下载完成");

       }

       //内部线程类

       private class DownloadThread extends Thread{

              private URL url;

              private File saveFile;

              private int block;//每条线程下载的数据长度

              private int threadid;//线程id

 

              public DownloadThread(URL url, File saveFile, int block, int threadid) {

                     this.url = url;

                     this.saveFile = saveFile;

                     this.block = block;

                     this.threadid = threadid;

              }

              public void run() {

                     //线程开始位置:线程id*每条线程下载的数据长度

                  //线程结束位置:(线程id +1*每条线程下载的数据长度-1

                     int startposition = threadid * block;

                     int endposition = (threadid + 1 ) * block - 1;

                     try {

                            RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rw");

                            accessFile.seek(startposition);//设置从什么位置开始写入数据

                            HttpURLConnection conn = (HttpURLConnection)url.openConnection();

                            conn.setRequestMethod("GET");

                            conn.setConnectTimeout(10 * 1000);

                            conn.setRequestProperty("Range", "bytes="+ startposition+ "-"+ endposition);//设置请求Range属性

                            InputStream inStream = conn.getInputStream();

                            byte[] buffer = new byte[1024];

                            int len = 0;

                            while( (len=inStream.read(buffer)) != -1 ){

                                   accessFile.write(buffer, 0, len);//通过accessFile向文件写数据

                            }

                            inStream.close();

                            accessFile.close();

                     } catch (Exception e) {

                            System.out.println("出现异常");

                     }

              }           

       }

 

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值