20150804-线程

一、基本知识

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

//线程1
public 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:我在等锁2
run2:我在等锁1
run2:我在使用锁1
run2:我使用完了锁1
run1:我在使用锁2
run2:我在等锁1
run1:我在等锁2
run2:我在使用锁1
run2:我使用完了锁1
run1:我在使用锁2
run2:我在等锁1
run1:我在等锁2
run2:我在使用锁1
run2:我使用完了锁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();

    }

}

演示:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值