目录
一、多线程
1.方法一:继承Thread类
2.方法二:实现Runnable接口
3.方法三:实现Callable接口
4.方法四:线程池
5.线程安全问题——同步
6.线程安全问题——死锁
7.线程通信
sleep() 和 wait() 有什么区别?
8.生产者消费者问题
二、网络编程
1.UDP
2.TCP
3.URL
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
}
}
}
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);
}
}
}
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();
}
}
}
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();
}
}
使用线程池的好处:
- 提高响应速度(减少创建新线程的时间)
- 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
- 便于线程管理
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();
}
}
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();
}
}
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();
}
}
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)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
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());
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();
}
}
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();
}
}
}
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