Java笔记(五)多线程+网络编程

目录

一、多线程

1.方法一:继承Thread类

2.方法二:实现Runnable接口

3.方法三:实现Callable接口 

4.方法四:线程池

5.线程安全问题——同步

6.线程安全问题——死锁

7.线程通信

sleep() 和 wait() 有什么区别?

8.生产者消费者问题

二、网络编程

1.UDP

2.TCP

3.URL


一、多线程

  • Java中的线程有五种状态:创建、就绪、运行、阻塞、结束

Java笔记(五)多线程+网络编程_第1张图片

1.方法一:继承Thread类

class MyThread extends Thread {
    MyThread() {
    }

    MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + "..." + i);
        }
    }
}

public class MyThreadTest {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        // 为线程对象设置名字
        myThread1.setName("myThread1");
        // 也可以在构造时设置名字
        MyThread myThread2 = new MyThread("myThread2");

        // 调用start方法开启线程,不是run方法
        myThread1.start();
        myThread2.start();

        // 获取线程优先级
        System.out.println(Thread.currentThread().getPriority());   // 5
        System.out.println(myThread1.getPriority());    // 5
        System.out.println(myThread2.getPriority());    // 5

        // 设置线程优先级
        // myThread1.setPriority(Thread.MAX_PRIORITY);
        // myThread2.setPriority(Thread.MIN_PRIORITY);

        for (int i = 0; i < 50; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "..." + i);
            // main线程阻塞,等待两个子线程执行完毕再继续执行
            if (i == 40) {
                try {
                    myThread1.join();
                    myThread2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 判断子线程是否存活
            System.out.println(myThread1.isAlive());    // false
            System.out.println(myThread2.isAlive());    // false
        }
    }
}

2.方法二:实现Runnable接口

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "..." + i);
        }
    }
}

/*
 * 好处:分离任务和线程对象,降低耦合性;实现变量共享
 */
public class MyRunnableTest {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.setName("myThread");
        thread.start();
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("匿名线程");
            }
        }).start();

        for (int i = 0; i < 50; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "..." + i);
        }
    }
}

3.方法三:实现Callable接口 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable {
    // call方法可以有返回值,也可以抛出异常
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
        return sum;
    }
}

public class CallableTest {
    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable();
        FutureTask futureTask = new FutureTask<>(myCallable);
        // FutureTask也实现了Runnable接口
        new Thread(futureTask).start();
        try {
            Object sum = futureTask.get();
            System.out.println(sum);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

4.方法四:线程池

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MyCallable implements Callable {
    @Override
    public String call() throws Exception {
        return "hello world";
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService eService = Executors.newFixedThreadPool(2);
        Future future = eService.submit(new MyCallable());
        System.out.println(future.get());
        eService.shutdown();
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class ThreadPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        // 设置线程池属性
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
        threadPoolExecutor.setCorePoolSize(10);
        
        Runnable runnable1 = () -> {
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (i % 2 != 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        };
        Runnable runnable2 = () -> {
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (i % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        };
        executorService.execute(runnable1);
        executorService.execute(runnable2);
        // executorService.submit(runnable1);
        // executorService.submit(runnable2);

        // executorService.submit(Callable callable);

        executorService.shutdown();
    }
}

使用线程池的好处:

  • 提高响应速度(减少创建新线程的时间)
  • 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
  • 便于线程管理

5.线程安全问题——同步

  • 一票多卖
class TicketThread extends Thread {
    private static int ticketCount = 100;

    TicketThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        while (true) {
            if (ticketCount > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName() + "..." + ticketCount);
                ticketCount--;
            }else {
                break;
            }
        }
    }
}

public class TicketTest {
    public static void main(String[] args) {
        new TicketThread("窗口1").start();
        new TicketThread("窗口2").start();
        new TicketThread("窗口3").start();
    }
}
class TicketRunnable implements Runnable {
    private int ticketCount = 100;

    @Override
    public void run() {
        while (true) {
            if (ticketCount > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "..." + ticketCount);
                ticketCount--;
            } else {
                break;
            }
        }
    }
}

public class TicketTest {
    public static void main(String[] args) {
        TicketRunnable ticketRunnable = new TicketRunnable();
        Thread thread1 = new Thread(ticketRunnable);
        thread1.setName("窗口1");
        thread1.start();
        Thread thread2 = new Thread(ticketRunnable);
        thread2.setName("窗口2");
        thread2.start();
        Thread thread3 = new Thread(ticketRunnable);
        thread3.setName("窗口3");
        thread3.start();
    }
}
  • 解决方法一:同步代码块
class TicketThread extends Thread {
    private static int ticketCount = 100;
    private static final Object obj = new Object();    // 同步锁,对象监视器

    TicketThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        while (true) {
            // synchronized (TicketThread.class) {
            synchronized (obj) {
                if (ticketCount > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "..." + ticketCount);
                    ticketCount--;
                } else {
                    break;
                }
            }
        }
    }
}

public class TicketTest {
    public static void main(String[] args) {
        new TicketThread("窗口1").start();
        new TicketThread("窗口2").start();
        new TicketThread("窗口3").start();
    }
}
class TicketRunnable implements Runnable {
    private int ticketCount = 100;
    private final Object obj = new Object();    // 同步锁,对象监视器

    @Override
    public void run() {
        while (true) {
            // synchronized (this) {
            synchronized (obj) {
                if (ticketCount > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "..." + ticketCount);
                    ticketCount--;
                } else {
                    break;
                }
            }
        }
    }
}

public class TicketTest {
    public static void main(String[] args) {
        TicketRunnable ticketRunnable = new TicketRunnable();
        Thread thread1 = new Thread(ticketRunnable);
        thread1.setName("窗口1");
        thread1.start();
        Thread thread2 = new Thread(ticketRunnable);
        thread2.setName("窗口2");
        thread2.start();
        Thread thread3 = new Thread(ticketRunnable);
        thread3.setName("窗口3");
        thread3.start();
    }
}
  • 解决方法二:同步方法
class TicketRunnable implements Runnable {
    private int ticketCount = 100;

    @Override
    public void run() {
        while (true) {
            saleTicket();
        }
    }

    // 同步非静态方法的对象锁为this
    private synchronized void saleTicket() {
        if (ticketCount > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "..." + ticketCount);
            ticketCount--;
        }
    }
}

public class TicketTest {
    public static void main(String[] args) {
        TicketRunnable ticketRunnable = new TicketRunnable();
        Thread thread1 = new Thread(ticketRunnable);
        thread1.setName("窗口1");
        thread1.start();
        Thread thread2 = new Thread(ticketRunnable);
        thread2.setName("窗口2");
        thread2.start();
        Thread thread3 = new Thread(ticketRunnable);
        thread3.setName("窗口3");
        thread3.start();
    }
}
class TicketThread extends Thread {
    private static int ticketCount = 100;

    TicketThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        while (true) {
            saleTicket();
        }
    }

    // 同步静态方法的对象锁为TicketThread.class
    private static synchronized void saleTicket() {
        if (ticketCount > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "..." + ticketCount);
            ticketCount--;
        }
    }
}

public class TicketTest {
    public static void main(String[] args) {
        new TicketThread("窗口1").start();
        new TicketThread("窗口2").start();
        new TicketThread("窗口3").start();
    }
}
  •  解决方法三:Lock对象锁
import java.util.concurrent.locks.ReentrantLock;

class TicketRunnable implements Runnable {
    private int ticketCount = 100;
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();
                if (ticketCount > 0) {
                    try {
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName() + "..." + ticketCount);
                        ticketCount--;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            } finally {
                lock.unlock();
            }

        }
    }
}

public class TicketTest {
    public static void main(String[] args) {
        TicketRunnable ticketRunnable = new TicketRunnable();
        Thread thread1 = new Thread(ticketRunnable);
        thread1.setName("窗口1");
        thread1.start();
        Thread thread2 = new Thread(ticketRunnable);
        thread2.setName("窗口2");
        thread2.start();
        Thread thread3 = new Thread(ticketRunnable);
        thread3.setName("窗口3");
        thread3.start();
    }
}

6.线程安全问题——死锁

  • 资源互斥,相互等待
public class DeadLockTest {
    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();
        new Thread(() -> {
            synchronized (obj1) {
                System.out.println("线程一拿到资源obj1");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程一等待资源obj2");
                synchronized (obj2) {
                    System.out.println("线程一拿到资源obj2");
                }
            }
        }).start();

        new Thread(() -> {
            synchronized (obj2) {
                System.out.println("线程二拿到资源obj2");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程二等待资源obj1");
                synchronized (obj1) {
                    System.out.println("线程二拿到资源obj1");
                }
            }
        }).start();
    }
}

7.线程通信

  • 线程同步——wait+notify
class Number implements Runnable {
    private int number = 1;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                notify();
                if (number <= 100) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number++;
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }
}

public class ThreadCommunicationTest {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);
        t1.setName("Thread-1");
        t2.setName("Thread-2");
        t1.start();
        t2.start();
    }
}

sleep() 和 wait() 有什么区别?

sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。

wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

 

8.生产者消费者问题

class Clerk {
    private int productCount = 0;

    synchronized void produce() {
        if (productCount < 20) {
            productCount++;
            System.out.println(Thread.currentThread().getName() + "开始生产第" + productCount + "个产品");
            notify();
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    synchronized void consume() {
        if (productCount > 0) {
            System.out.println(Thread.currentThread().getName() + "开始消费第" + productCount + "个产品");
            productCount--;
            notify();
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Producer extends Thread {
    private Clerk clerk;

    Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + ":开始生产产品...");
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.produce();
        }
    }
}

class Customer extends Thread {
    private Clerk clerk;

    Customer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + ":开始消费产品");
        while (true) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consume();
        }
    }
}

public class ProducerCustomer {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        producer.setName("生产者");

        Customer customer = new Customer(clerk);
        customer.setName("消费者");

        producer.start();
        customer.start();
    }
}

二、网络编程

InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
InetAddress inetAddress2 = InetAddress.getByName("localhost");
InetAddress inetAddress3 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress1);
System.out.println(inetAddress2);
System.out.println(inetAddress3);
System.out.println("--------------------------------------");
InetAddress inetAddress =InetAddress.getLocalHost();
System.out.println(inetAddress);
System.out.println(inetAddress.getHostName());
System.out.println(inetAddress.getHostAddress());
  • Tomcat端口号8080,MySQL端口号3306,Oracle端口号1521

1.UDP

package UDP;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Sender {
    public static void main(String[] args) throws IOException {
        byte[] msg = "Hello world!".getBytes();
        InetAddress inetAddress = InetAddress.getByName("127.0.0.1");  // 目的地址
        DatagramPacket packet = new DatagramPacket(msg, msg.length, inetAddress, 6000);    // 将数据,目的地址,端口号等信息封装为数据报
        DatagramSocket socket = new DatagramSocket();   // 数据报传输套接字
        socket.send(packet);
        socket.close();
    }
}
package UDP;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Receiver {
    public static void main(String[] args) throws IOException {
        byte[] msg = new byte[1024];
        DatagramPacket packet = new DatagramPacket(msg, msg.length);    // 数据报对象
        DatagramSocket socket = new DatagramSocket(6000);   // 数据报传输套接字
        socket.receive(packet);
        int length = packet.getLength();    // 获取数据报中的数据部分长度
        String message = new String(msg, 0, length);
        System.out.println(message);
        socket.close();
    }
}

2.TCP

package TCP;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("127.0.0.1", 6522);
             FileInputStream fileInputStream = new FileInputStream("d:\\a.log")) {
            OutputStream outputStream = socket.getOutputStream();
            InputStream inputStream = socket.getInputStream();
            outputStream.write("Client is ready to transfer files.".getBytes());    // 通知服务器客户端已准备就绪
            byte[] buf = new byte[1024];
            int len = inputStream.read(buf);    // 接收服务器准备就绪信息
            System.out.println(new String(buf, 0, len));

            System.out.println("Transferring...");
            while((len = fileInputStream.read(buf))!=-1){
                outputStream.write(buf,0,len);
            }
            socket.shutdownOutput();    // 向服务器写入一个终止标志

            // 接收服务器的传输成功
            len = inputStream.read(buf);
            System.out.println(new String(buf,0,len));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package TCP;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

public class Server {
    public static void main(String[] args) {
        //规则:  域名+毫秒值+6位随机数
        String filename = "lee" + System.currentTimeMillis() + String.format("%06d", new Random().nextInt(999999)) + ".log";
        try (ServerSocket serverSocket = new ServerSocket(6522);
             FileOutputStream fileOutputStream = new FileOutputStream("d:\\" + filename)) {
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            byte[] buf = new byte[1024];
            int len = inputStream.read(buf);
            System.out.println(new String(buf, 0, len));
            outputStream.write("Server is ready to receive files.".getBytes());

            System.out.println("Receiving...");
            while ((len = inputStream.read(buf)) != -1) {
                fileOutputStream.write(buf, 0, len);
            }
            System.out.println("File Received.");
            outputStream.write("File Received.".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

加入多线程的服务器

package TCP;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

public class MultiThreadServer {
    public static void main(String[] args) {
        try(ServerSocket serverSocket = new ServerSocket(6522)){
            while (true) {
                Socket socket = serverSocket.accept();
                new Thread(new Upload(socket)).start();
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

class Upload implements Runnable {
    private Socket socket;

    public Upload(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //规则:  域名+毫秒值+6位随机数
        String filename = "lee" + System.currentTimeMillis() + 
                    String.format("%06d", new Random().nextInt(999999)) + ".log";
        try (FileOutputStream fileOutputStream = new FileOutputStream("d:\\" + filename)) {
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            byte[] buf = new byte[1024];
            int len = inputStream.read(buf);    // 接收客户端准备就绪信息
            System.out.println(new String(buf, 0, len));
            outputStream.write("Server is ready to receive files.".getBytes()); // 通知服务器已准备就绪

            System.out.println("Receiving...");
            while ((len = inputStream.read(buf)) != -1) {
                fileOutputStream.write(buf, 0, len);
            }
            System.out.println("File Received.");
            outputStream.write("File Received.".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.URL

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

class URLTest {
    public static void main(String[] args) {
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            URL url = new URL("http://localhost:8080/examples/hello.txt");
            System.out.println(url.getProtocol());
            System.out.println(url.getHost());
            System.out.println(url.getPort());
            System.out.println(url.getPath());
            System.out.println(url.getFile());
            System.out.println(url.getQuery());

            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.connect();
            inputStream = urlConnection.getInputStream();
            fileOutputStream = new FileOutputStream("test.txt");
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
    }
}

 

参考书籍:《疯狂Java讲义》

参考文章:http://www.runoob.com/java/java-tutorial.html

你可能感兴趣的:(Java)