UDP编程:
发送端只发送信息,不管信息是否发送成功。
import java.io.IOException;
import java.net.*;
public class Send {
public static void main(String[] args) throws IOException {
//发送端
DatagramSocket datagramSocket = new DatagramSocket();
byte [] bytes = "你好接收端".getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"),9999);
datagramSocket.send(datagramPacket);
datagramSocket.close();
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Receive {
public static void main(String[] args) throws IOException {
//接收端
DatagramSocket datagramSocket = new DatagramSocket(9999);
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(datagramPacket);//接收
String s = new String(datagramPacket.getData(),0,datagramPacket.getLength());
System.out.println(s);
}
}
线程:
1、程序、进程、线程:
程序:为完成某种特定的功能,使用计算机语言编写的一系列指令的集合,即静态代码
进程:运行中的程序,是操作系统分配资源的最小单位
线程:进程内部最小的执行单元(具体要做的一件事情),是操作系统进行任务调度的最小单位
2、进程与线程的关系:
一个进程中可以包含多个线程,线程必须属于某一个进程,不能独立存在
一个进程中必须有一个主线程,在主线程中可以创建其他子线程
一个进程中的所有线程,共享该进程中的所有资源
3、Java中如何创建线程(除main线程之外的线程):
main方法是用来启动Java主线程的,是一个线程,一个线程内部,是按照从上到下依次执行的
方法一:继承Thread
//继承了Thread,所以就拥有了Thread类定义的管理线程的方法
public class ThreadDemo extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("ThreadDemo:"+i);
}
}
}
public class TestThreadDemo {
public static void main(String[] args) {
ThreadDemo t = new ThreadDemo();
//t.run();//注意,zh不是启动线程,只是普通的方法调用
t.start();//启动线程
for (int i = 0; i < 1000; i++) {
System.out.println("main:"+i);
}
}
}
方法二:实现Runnable接口
//实现Runnable接口,并没有继承Thread类,只是重写了run(),可以编写线程中要执行的功能,本身并不是线程
public class RunTask implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("RunTask:"+i);
}
}
}
public class Test {
public static void main(String[] args) {
RunTask runTask = new RunTask();//创建一个执行任务的对象
Thread thread = new Thread(runTask);//创建线程对象后,为线程添加一个执行的任务
thread.start();//启动线程
for (int i = 0; i < 1000; i++) {
System.out.println("main:"+i);
}
}
}
区别:
1、继承Thread类之后,由于Java是单继承的,所有就不能继承其他类了,实现Rannable接口的方式,此时还可以继承其他类
2、共享资源的区别。例如在多窗口售票例题中,使用继承Thread类的方法,必须用static修饰票数,否则在测试时多窗口不能共享票数。然而,在使用实现Rannable接口的方法,票数不需要用static修饰,因为在测试时只创建一个任务对象,创建多个线程运行同一个任务对象,票数是共享的。
4、Thread类中的方法:
public class RunTask implements Runnable{
//用来写线程要执行的逻辑(代码)
@Override
public void run() {
//System.out.println(Thread.currentThread().getId());//获取当前正在执行的线程的id
//System.out.println(Thread.currentThread().getName());//获取当前正在执行的线程的名字
System.out.println(Thread.currentThread().getPriority());//获取当前线程优先级
}
}
public class Test {
public static void main(String[] args) {
RunTask runTask = new RunTask();
// Thread thread = new Thread(runTask);//创建线程对象后,为线程添加一个执行的任务
Thread thread = new Thread(runTask,"myTheard1");//创建线程对象后,为线程添加一个执行的任务,并为线程命名
thread.start();//启动线程
/*
currentThread();//获取当前正在执行的线程
getId();//获取线程的id
getName();//获取线程的名字
*/
//System.out.println(Thread.currentThread().getId());//获取当前正在执行的线程的id
//System.out.println(Thread.currentThread().getName());//获取当前正在执行的线程的名字
//thread.setPriority(10);//设置线程优先级,优先级1-10,默认为5
//getPriority();//获取线程优先级
System.out.println(Thread.currentThread().getPriority());//获取当前线程优先级
}
}
5、线程状态(线程的生命周期):
6、守护线程:
Java中的线程分为两类:用户线程和守护线程
守护线程为其他线程提供服务,最大的特点是,当系统其他的用户线程结束后,守护线程会自动结束eg:jvm中的垃圾回收线程就是一个守护线程
示例:
public class DaemonThread extends Thread {
@Override
public void run() {
int i = 0;
while(true){
System.out.println("DaemonThread:"+i++);
}
}
}
public class Test {
public static void main(String[] args) {
DaemonThread daemonThread = new DaemonThread();
daemonThread.setDaemon(true);//设置该线程为守护线程,守护线程必须在启动线程之前设置,否则会抛出一个IllegalThreadStateException异常
daemonThread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("main:"+i);
}
}
}
多线程:
指的是程序内部,可以创建多个线程执行不同的任务
什么时候需要多线程?
需要可以同时执行多个不同任务,eg:杀毒软件,QQ
优点:
提高程序的响应,提高cpu的利用率,改善程序结构
缺点:
占用内存;占用cpu资源,需要多线程进行管理;多线程同时对共享资源进行访问,如果不加以控制,会出现线程安全问题
线程同步:
并发:在一个时间段内,多个任务依次执行
并行:是真正意义上的同时执行,一个时间节点上有多个任务同时执行。
处理线程同步问题:加锁,让线程一个一个执行,例如:模拟售票
使用synchronized关键字:
可以修饰一段代码块,
synchronized (同步锁/同步对象){ }
同步对象要求: 多个线程必须访问到的是同一个对象,对象用来记录有没有线程进入到同步代码块中
也可以修饰一个方法,synchronized修饰方法时,锁对象有两种情况:
1、修饰的是非静态方法,锁对象默认是this
2、修饰的是静态方法,锁对象是该类的Class对象
例题:多个窗口售票问题(对代码块进行加锁)
方法一:继承Thread
/*
由于继承的是Thread类方法,创建两个TicketThread对象,
如果不加static修饰num,那么num在每一个对象中都有一个num.
用static修饰后,num在内存中就只有一份了,两个线程对象共享的就是同一个num了
synchronized修饰一段代码块,也可以修饰一个方法
synchronized (同步锁/同步对象){
}
同步对象要求: 多个线程必须访问到的是同一个对象,对象用来记录有没有线程进入到同步代码块中
*/
public class TicketThread extends Thread{
static int num = 10;
static Object object = new Object();
@Override
public void run() {
while(true){
synchronized (object){
if(num>0){
System.out.println(Thread.currentThread().getName()+":"+num);
num--;
}else{
break;
}
}
}
}
}
public class Test {
public static void main(String[] args) {
TicketThread t1 = new TicketThread();
t1.setName("窗口1");
TicketThread t2 = new TicketThread();
t2.setName("窗口2");
t1.start();
t2.start();
}
}
方法二:实现Runnable接口
public class TicketTask implements Runnable{
int num = 10;
@Override
public void run() {
while(true){
synchronized (this){
if(num>0){
System.out.println(Thread.currentThread().getName()+":"+num);
num--;
}else{
break;
}
}
}
}
}
public class Test {
public static void main(String[] args) {
TicketTask ticketTask = new TicketTask();
Thread t1 = new Thread(ticketTask,"窗口1");
t1.start();
Thread t2 = new Thread(ticketTask,"窗口2");
t2.start();
}
}