20150804-线程

来源:互联网 发布:警惕网络炒汇陷阱 编辑:程序博客网 时间:2024/06/06 03:47

  • 一基本知识
  • 二创建线程的方法
    • 方法一继承Thread类javalangThread
    • 方法二实现Runnable接口javalangRunnable
  • 三利用线程的经典范例
    • 范例8
    • 范例9
    • 范例10

一、基本知识

1.定义:
线程:是进程中的一个独立的控制单元,线程控制着进程的执行;线程之间共享进程中的数据。
进程:是单独的内存空间,进程之间不能共享数据。一个进程中至少会有一个线程。
2.延伸:
jvm启动就不止一个线程,还有垃圾回收机制的线程。

二、创建线程的方法

方法一):继承Thread类(java.lang.Thread)

1.步骤:
1)继承Thread类
2)重写run方法
3)调用线程的start方法(作用是启动线程调用run方法,且申请一块内存空间,进行新线程的执行)
2.简单范例1:
/*利用继承的方法实现新线程
*/

//创建线程public class MyThread extends Thread{    @Override    public void run(){        System.out.println("我是一个新的线程!");    }}

//测试:

/*这里包括新创建的线程和主线程。*/public class TestThread {    public static void main(String[] args) {        MyThread mt = new MyThread();        System.out.println("线程开始!");        mt.start();  //一定不用调用run方法        try {            mt.sleep(50);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println("线程结束!");    }}/*结果:(顺序不唯一)线程开始!我是一个新的线程!线程结束!*/

3.范例2:实现售票:

public class ThreadTicket extends Thread{    private int ticketNum = 200;    public ThreadTicket(){    }    public ThreadTicket(String name){        super(name);    //由于要传参,调用父类Thread类中传参数的构造方法    }    @Override    public void run() {        while(ticketNum>0){            //利用getName方法获得线程名称,因为用的传参构造器,在创建对象可以输入名称。        System.out.println(getName()+"卖出第"+ticketNum--+"张票");        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        }    }}
//测试:public class TestTicket {    public static void main(String[] args) {        ThreadTicket t1 = new ThreadTicket("售票口1");        ThreadTicket t2 = new ThreadTicket("售票口2");        ThreadTicket t3 = new ThreadTicket("售票口3");        ThreadTicket t4 = new ThreadTicket("售票口4");        t1.start();        t2.start();        t3.start();        t4.start();    }}/*部分结果:(可以发现一张票多次被卖出,与缺陷,下面将介绍用实现Runnable的方法)售票口2卖出第200张票售票口3卖出第200张票售票口1卖出第200张票售票口4卖出第200张票售票口2卖出第199张票售票口1卖出第199张票售票口4卖出第199张票售票口3卖出第199张票售票口4卖出第198张票售票口3卖出第198张票售票口2卖出第198张票售票口1卖出第198张票*/

方法二)实现Runnable接口(java.lang.Runnable)

1.好处:
避免了单继承的局限性,定义线程时,建议使用实现的方式。
2.方法:也要实现run方法。
3.注:
构建对象时,只需建一个自定义的线程对象:
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr,”名字”);
4.范例3:
/*
要求:利用实现Runnable实现售票功能,四个窗口,20张票。
*/

/*买票线程:步骤:1.实现run方法2.利用同步代码块,防止同一张票被多次卖出3.同步代码块中,需再次判断ticketNum>0,避免多个线程都在等锁,进入后数值减到负值。*/public class MyRunnable implements Runnable{    private int ticketNum = 20;    private String mutex="qw";    @Override    public void run() {        while(ticketNum>0){            try {                Thread.sleep(500);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            //同步代码块            //注:当1234线程都在等时,一旦锁被释放,线程就都进入买票,这时容易出现负值。            synchronized (mutex) { //加锁                if(ticketNum>0){  //保证不会产生负数值。                    System.out.println(Thread.currentThread().getName()+"卖出第"+ticketNum+"张票");                    ticketNum--;                }            }           }    }}
//测试:public class TestRunnable {    public static void main(String[] args) {        MyRunnable runnable =  new MyRunnable(); //只建立了一个MyRunnable,然后里面的线程共享资源        Thread t1 = new Thread(runnable,"售票口1");         Thread t2 = new Thread(runnable,"售票口2");        Thread t3 = new Thread(runnable,"售票口3");        Thread t4 = new Thread(runnable,"售票口4");        t3.setPriority(10);//t3线程的优先级设为最高,但并不表示t3一定每次都先抢到。        t1.start();        t2.start();        t3.start();        t4.start();    }}/*结果:售票口3卖出第20张票售票口1卖出第19张票售票口4卖出第18张票售票口2卖出第17张票售票口1卖出第16张票售票口3卖出第15张票售票口4卖出第14张票售票口2卖出第13张票售票口3卖出第12张票售票口4卖出第11张票售票口1卖出第10张票售票口2卖出第9张票售票口1卖出第8张票售票口4卖出第7张票售票口3卖出第6张票售票口2卖出第5张票售票口1卖出第4张票售票口4卖出第3张票售票口3卖出第2张票售票口2卖出第1张票*/

5.方法介绍:
1)同步代码块
同步方法:同步方法的锁调用该方法的对象。
public synchronized void methodA(){}
表示执行这个方法的线程互斥。
2)优先级:t3.setPriority(10);//并不绝对
1-10(默认为5)
3)join()方法:暂停当前正在执行的线程对象,并执行其他线程,用来“临时释放”(不用建立对象,直接Thread.yield())
范例4:

public class TestRunnble2 {    public static void main(String[] args) {        MyRunnable mr = new MyRunnable();        Thread t1 = new Thread(mr,"售票1");        t1.start();        try {            t1.join();            //t1.join(500);//t1线程先运行0.5ms,以后再运行别的程序。        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println("主线程售票结束!");    }}

6范例5:
/*
要求:两人同时从同一个账户取钱,每次取100,一共账户存了1000;
*/

//线程public class RunnableBank implements Runnable{    private int moneyNumALL=1000;    private String mutex="ad";    @Override    public void run() {        while(moneyNumALL>0){            try {                Thread.sleep(50);   //仅控制取钱的速度。            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            synchronized (mutex) {                if(moneyNumALL>=0){                    System.out.println(Thread.currentThread().getName()+"取走钱后剩下-->"+moneyNumALL+"元");                    moneyNumALL=moneyNumALL-100;                }            }        }           }}
//测试:public class TestBank {    public static void main(String[] args) {        RunnableBank runnable = new RunnableBank();        Thread t1 = new Thread(runnable,"张三"); //规范形式,强记        Thread t2 = new Thread(runnable,"王五");        t1.start();        t2.start();    }}/*结果:王五取走钱后剩下-->1000元张三取走钱后剩下-->900元王五取走钱后剩下-->800元张三取走钱后剩下-->700元张三取走钱后剩下-->600元王五取走钱后剩下-->500元张三取走钱后剩下-->400元王五取走钱后剩下-->300元王五取走钱后剩下-->200元张三取走钱后剩下-->100元王五取走钱后剩下-->0元*/

7.死锁
注:
锁不可以是int类型。

范例6:
注:这里在两个线程定义的锁都是相同的,因为他们字符串相同,在内存中缓存区原存入了值,下一个相同的字符创建立时就不再开辟新的区域。

//线程1public class RunnableSisuo1 implements Runnable{    String mutex1 = "a";    String mutex2 = "b";    @Override    public void run() {        synchronized (mutex1) {            try {                Thread.sleep(500);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            System.out.println("我在等mutex2锁");            synchronized (mutex2) {                System.out.println(Thread.currentThread().getName()+"正在运行");            }        }    }}
//线程2:public class RunnableSisuo2 implements Runnable{    String mutex1 = "a";    String mutex2 = "b";    @Override    public void run() {        synchronized (mutex2) {            try {                Thread.sleep(500);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            System.out.println("我在等mutex1锁");            synchronized (mutex1) {                System.out.println(Thread.currentThread().getName()+"正在运行");            }        }    }}
//测试:public class TestSisuo {    public static void main(String[] args) {        RunnableSisuo1 runnable1 = new RunnableSisuo1();        RunnableSisuo2 runnable2 = new RunnableSisuo2();        Thread t1 = new Thread(runnable1,"线程1");        Thread t2 = new Thread(runnable2,"线程2");        t1.start();        t2.start();    }}/*结果:我在等mutex1锁我在等mutex2锁*/

范例7:
/*死锁的解决:
通过object中的wait方法先释放锁,待到其他线程先使用完锁后,在notify唤醒锁即可。结构: lock.wait();
*/

//线程1:public class MyRunnable1 implements Runnable{    String lock1 = "q";    String lock2 = "w";    @Override    public void run() {        while(true){        try {            Thread.sleep(500);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        synchronized (lock1) {            System.out.println("run1:我在等锁2");            try {                lock1.wait();//释放锁1,锁被run2使用后,唤醒锁,run1才能使用            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }  //释放锁1,            synchronized (lock2) {                System.out.println("run1:我在使用锁2");            }        }        }    }}
//线程2:public class MyRunnable2 implements Runnable{    String lock1 = "q";    String lock2 = "w";    @Override    public void run() {        while(true){        try {            Thread.sleep(500);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        synchronized (lock2) {            System.out.println("run2:我在等锁1");            synchronized (lock1) {                System.out.println("run2:我在使用锁1");                lock1.notify();                System.out.println("run2:我使用完了锁1");             }        }        }    }}
//测试:public class TestRunnable {/*lock1.wait():锁1释放后,run2使用锁1;且注意run2唤醒锁后还需要将程序执行完后才会释放掉锁1,并不是一notify就释放锁。 * wait():在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待 * */    public static void main(String[] args) {        MyRunnable1 runnable1 = new MyRunnable1();        MyRunnable2 runnable2 = new MyRunnable2();        Thread t1 = new Thread(runnable1);        Thread t2 = new Thread(runnable2);        t1.start();        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        t2.start();    }}/*结果:run1:我在等锁2run2:我在等锁1run2:我在使用锁1run2:我使用完了锁1run1:我在使用锁2run2:我在等锁1run1:我在等锁2run2:我在使用锁1run2:我使用完了锁1run1:我在使用锁2run2:我在等锁1run1:我在等锁2run2:我在使用锁1run2:我使用完了锁1*/

三、利用线程的经典范例:

范例8:

/*生产者与消费者问题:
要求:生产者生产一个产品,消费者消费一个产品。
(注意:
1)生产者和消费者是两个不同的线程。
2)由于两个线程共用产品资源,所以这里将产品另创一个类。
3)以产品作为锁即可。当产品数为0时,生产者生产;当产品数为1时,消费者消费。
4)避免使生产者或者消费者重复抢到锁,再退出(方法:生产者生产完后,休眠一段时间,并释放锁,消费者消费完后,休眠一段时间并唤醒锁)

思路:(休眠的时间问题)
1.生产者和消费者如果都先休眠等同时间再抢,且在主线程中也是中间没有休眠暂停时间,,那么可能出现一个线程多次抢到锁。所以在主线程中可以让两者中间隔一段时间。
*/

//产品类:public class Protuction {    private int proNum;    public int getProNum() {        return proNum;    }    public void setProNum(int proNum) {        this.proNum = proNum;    }}
//生产者:public class Produce implements Runnable{    private Protuction pro;    public Produce(Protuction pro){ //通过构造器获得产品类型        this.pro = pro;    }    @Override    public void run() {        while(true){            try {                Thread.sleep(1000); //先休眠1s再抢锁            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            synchronized(pro){                System.out.println("生产者抢到锁");                if(pro.getProNum()==0){                    System.out.println("生产者生产");                    pro.setProNum(1);                    try {                        pro.wait();                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }            }        }       }}
//消费者:public class Consumer implements Runnable{    private Protuction pro;    public Consumer(Protuction pro){        this.pro = pro;    }    @Override    public void run() {        while(true){            try {                Thread.sleep(1000);//先休眠1s再抢锁            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            synchronized (pro) {                System.out.println("消费者抢到锁");                if(pro.getProNum()!=0){                    System.out.println("消费者消费");                    pro.setProNum(0);                    pro.notify();                }            }               }    }}
//测试:public class Test01 {    public static void main(String[] args) {        Protuction pro = new Protuction();        Thread produce = new Thread(new Produce(pro));        Thread consumer = new Thread(new Consumer(pro));        produce.start();        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        consumer.start();    }}/*结果:生产者抢到锁生产者生产消费者抢到锁消费者消费生产者抢到锁生产者生产消费者抢到锁消费者消费生产者抢到锁生产者生产消费者抢到锁消费者消费*/

范例9:

/*聊天程序:
要求:利用TCP和多线程的方式,客户端和服务端聊天,发送和接收不限次数。
思路:
1.分别建立客户端、服务端,以及读线程和写线程。
2.客户端和服务端:1)各自分别建立socket和serversocket对象,注意客户端参数是发送到的目的ip及端口,服务器端设好监听的端口。2)都建立读和写两个线程对象,且都start即可。
3.由于客户端和服务器端在读和写的操作是一样的,且需要不同步,所以将读和写操作分别写入两个线程中。
4.在两个线程中获得socket的方式都是通过构造器传入。
*/
代码:

//客户端:public class Client {    public static void main(String[] args) {        try {            System.out.println("客户端启动:");            Socket socket = new Socket(InetAddress.getByName("192.168.0.74"), 8080);            Thread read = new Thread(new MyRead(socket));            Thread write = new Thread(new MyWrite(socket));            read.start();            write.start();        } catch (UnknownHostException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}
//服务器端:public class Server {    public static void main(String[] args) {        try {            System.out.println("服务器端启动:");            ServerSocket serversocket = new ServerSocket(8080);            Socket socket = serversocket.accept();            Thread read = new Thread(new MyRead(socket));            Thread write = new Thread(new MyWrite(socket));            read.start();            write.start();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}
//读线程:public class MyRead implements Runnable{    private Socket socket;    public MyRead(Socket socket){  //传入socket        this.socket = socket;    }    @Override    public void run() {        BufferedReader br = null;        try {            InputStream is = socket.getInputStream();//获取读输入流            br = new BufferedReader(new InputStreamReader(is));            while(true){                String s = br.readLine();                System.out.println(s);            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}
//写线程:public class MyWrite implements Runnable{    private Socket socket;    public MyWrite(Socket socket){  //传入socket        this.socket = socket;    }    @Override    public void run() {        BufferedWriter bw = null;        try {            OutputStream os = socket.getOutputStream();//获取读输入流            bw = new BufferedWriter(new OutputStreamWriter(os));            Scanner sanner = new Scanner(System.in);            while(true){                String s = sanner.nextLine();                bw.write(s+"\n");                bw.flush();                System.out.println(s);            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

结果演示:
这里写图片描述

范例10:

/*图形界面java聊天设计:
思路:
1.共有客户端和服务器端和两个端的读方法在不同的线程中
2.首先,导入software,使可以进行图形化设计,方法:
help–>install software–>添加压缩包,将下面所有对勾勾掉,上面打上勾,next安装,重启。
3.MyClient和MyServer都是通过创建JFram文件,通过拖拉元件直接获得界面,当双击进入按钮时,按钮获得点击事件,可以通过修改java代码进行完善。
4.MyClient和MyServer都写入read方法和write方法。
5.由于写即发送时通过按钮点击,所以只要在按钮的点击事件中调用write方法即可。而读方法,是在一直都在等着读,所以讲读方法写在线程中,且在建立连接按钮的监听事件中创建好线程。
6.将读方法调到线程的方法:利用构造器。注:read方法一定写到while循环中。
7.涉及几个用法:1)通过model将发送或读到的数据显示到list中:
DefaultListModel model = new DefaultListModel<>();
list.setModel();
model.addElement(“服务器返回说:”+line);
2)获取text中的值:
String words= textArea.getText();

*/

//客户端:package com.day0805_swing;/*注释:有MyClient和MyServer两个端,在其中的连接事件分别建立了线程,线程只使用了在端中定义的读和写的方法。 * 注:将读的方法定义到线程中去。 *  * */import java.awt.BorderLayout;import java.awt.EventQueue;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.Socket;import java.net.UnknownHostException;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.border.EmptyBorder;import javax.swing.JEditorPane;import javax.swing.DefaultListModel;import javax.swing.JButton;import javax.swing.JList;import javax.swing.JTextArea;import java.awt.event.ActionListener;import java.awt.event.ActionEvent;public class MyClient extends JFrame {    private JPanel contentPane;    private Socket socket;//1.定义一个socket    DefaultListModel<String> model;    JTextArea textArea;    /**     * Launch the application.     */    public static void main(String[] args) {        EventQueue.invokeLater(new Runnable() {            public void run() {                try {                    MyClient frame = new MyClient();                    frame.setVisible(true);                } catch (Exception e) {                    e.printStackTrace();                }            }        });    }    /**     * Create the frame.     */    public MyClient() {        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        setBounds(100, 100, 450, 300);        contentPane = new JPanel();        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));        setContentPane(contentPane);        contentPane.setLayout(null);        JButton btnNewButton = new JButton("建立连接");        btnNewButton.addActionListener(new ActionListener() {            public void actionPerformed(ActionEvent e) {//5.点击事件,建立连接                System.out.println("连接服务器:");                try {                    socket =new Socket("192.168.0.74", 8080);                    System.out.println("连接成功");                    //连接成功后建立线程                    Thread t = new Thread(new MyClientRead(MyClient.this));                    t.start();                } catch (UnknownHostException e1) {                    // TODO Auto-generated catch block                    e1.printStackTrace();                } catch (IOException e1) {                    // TODO Auto-generated catch block                    e1.printStackTrace();                }//去连接8080端口            }        });        btnNewButton.setBounds(275, 36, 93, 44);        contentPane.add(btnNewButton);        JButton btnNewButton_1 = new JButton("发送");        btnNewButton_1.addActionListener(new ActionListener() {            public void actionPerformed(ActionEvent e) {//4、点击事件,发送                write();            }        });        btnNewButton_1.setBounds(294, 208, 74, 44);        contentPane.add(btnNewButton_1);        JList list = new JList();        list.setBounds(10, 10, 255, 188);         model = new DefaultListModel<>(); //3.建立一个model,让数据可以添加进去         list.setModel(model);         contentPane.add(list);        textArea = new JTextArea();//4.使textArea可获取        textArea.setBounds(20, 208, 232, 44);        contentPane.add(textArea);    }    /*2、1)定义一个读方法:客户端读是读取流中数据,即服务器传过来的,且读入后需要将数据显示到list中。(这是与服务器的读不同的地方,)    服务器读完不用写入list,因为客户端发送会在list中显示。     2)写到list中采用modle方式    *    */    public void read() {        try {            InputStream is = socket.getInputStream();            BufferedReader br = new BufferedReader(new InputStreamReader(is));            String line = br.readLine();            System.out.println("接收到服务器的返回信息:"+line);//控制台输出一遍            //先做3步骤            model.addElement("服务器返回说:"+line);//将返回值加到model中        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    /*3.定义写方法:1)将写到text中的数据写到服务器,以及list中。     * */    public void write(){        try {            OutputStream os=socket.getOutputStream();            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(os));            String words=   textArea.getText(); //先进行4步骤,将textArea可获取            System.out.println("客户端发送信息:"+words);            model.addElement(words+"\n");//将发送的数据写到list中            bw.write(words+"\n");            textArea.setText("");            bw.flush();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}
//服务器端:package com.day0805_swing;import java.awt.BorderLayout;import java.awt.EventQueue;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.border.EmptyBorder;import javax.swing.JButton;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.ServerSocket;import java.net.Socket;import java.awt.event.ActionEvent;import javax.swing.JTextArea;public class MyServer extends JFrame {    private JPanel contentPane;    private Socket socket; //1.定义一个Socket    private boolean isRunning=true;//3定义一个连接的判断并定义get,set方法    JTextArea textArea;//5.使textArea可以被访问到    public  boolean isRunning(){        return isRunning;    }    public void setRunning(boolean isRunning) {        this.isRunning = isRunning;    }    /**     * Launch the application.     */    public static void main(String[] args) {        EventQueue.invokeLater(new Runnable() {            public void run() {                try {                    MyServer frame = new MyServer();                    frame.setVisible(true);                } catch (Exception e) {                    e.printStackTrace();                }            }        });    }    /**     * Create the frame.     */    public MyServer() {        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        setBounds(100, 100, 450, 300);        contentPane = new JPanel();        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));        setContentPane(contentPane);        contentPane.setLayout(null);        JButton btnNewButton = new JButton("启动服务!");        btnNewButton.addActionListener(new ActionListener() {            public void actionPerformed(ActionEvent e) {//7.监听事件,点击:服务器启动                try {                    ServerSocket server = new ServerSocket(8080);                    System.out.println("服务器已启动!");                    socket = server.accept(); //等待连接                    System.out.println("有客户机连接!");                    //连接完成后就可以建立线程进行读写。                    Thread t = new Thread(new MyServerRead(MyServer.this));//注:传入的对象?                    t.start();                } catch (IOException e1) {                    // TODO Auto-generated catch block                    e1.printStackTrace();                }            }        });        btnNewButton.setBounds(46, 24, 179, 56);        contentPane.add(btnNewButton);         textArea = new JTextArea();        textArea.setBounds(24, 170, 289, 82);        contentPane.add(textArea);        JButton btnNewButton_1 = new JButton("发送给客户机");        btnNewButton_1.addActionListener(new ActionListener() {            public void actionPerformed(ActionEvent e) {                write();  //6.调用写方法发送值,按钮的监听事件            }        });        btnNewButton_1.setBounds(326, 182, 86, 48);        contentPane.add(btnNewButton_1);    }    //2.定义读方法:    public void read(){        try {            InputStream is = socket.getInputStream();            BufferedReader br = new BufferedReader(new InputStreamReader(is));            String line= br.readLine();            System.out.println("服务器接收到的信息:"+line);//读到的数据显示在控制台        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    //4.定义写方法    public void write(){        try {            OutputStream os = socket.getOutputStream();            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));            System.out.println("服务器器发送信息:");            //从text窗口获得写入的值,修改上面textArea的访问范围,使其可以访问            String word = textArea.getText();            bw.write(word+"\n");//1)将值发给客户机            textArea.setText("");//将窗口清空            bw.flush();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}
//客户端读线程:public class MyClientRead implements Runnable{    private MyClient client;    public MyClientRead(MyClient client){        this.client = client;    }    @Override    public void run() {        client.read();    }}
//服务器端读线程:public class MyServerRead implements Runnable{//需要获取到在类MyServer中的读方法    private MyServer myserver; //通过结构体获得,对象一构建,便有一个MyServer    public  MyServerRead(MyServer myserver) {        this.myserver = myserver;    }    @Override    public void run() {        myserver.read();    }}

演示:
这里写图片描述

0 0
原创粉丝点击