新手初学Java网络编程

目录
  • 运行线程
    • 回调
    • 同步方法
    • 同步块
    • 死锁
    • 优先级
    • 暂停
      • 可以对IO阻塞
      • 可以对同步对象阻塞
      • 可以放弃
      • 可以休眠
      • 可以连接另一个线程
      • 可以等待一个对象
      • 可以结束
    • 可以被更高优先级线程抢占
  • 总结

运行线程

创建Thread的子类

public class ThreadChild extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        ThreadChild t = new ThreadChild();
        t.start();
    }
}

创建Thread传入Runnable接口实现类

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new RunnableImpl());
        t.start();
    }
}

回调

ExecutorService线程池的Submit()可接收Runnable或者Callable.Callable执行结束后有返回值,Runnable执行结束后没有返回值.可以通过submit的返回对象Future的get方法获取返回返回值,需要注意的是get方法是一个阻塞方法.若线程没有执行完毕,则会阻塞get()直到线程执行结束后返回数据.

public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Integer> future = executorService.submit(() -> {
            TimeUnit.SECONDS.sleep( 3);
            return 1;
        });
        Future<?> future2 = executorService.submit(() -> {
        });
        Future<String> future3 = executorService.submit(() -> {
        }, "aaa");
        System.out.println(future.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
    }

同步方法

synchronized关键字和方法组合使用后,该方法是一个同步方法。同步方法都有一个隐试的锁,多个线程同时执行该方法时,只能顺序执行,未强到锁的线程处于阻塞状态。另外静态方法和非静态方法使用的是不同的锁,非静态方法的锁是对象锁,若两个线程通过两个该类的对象调用那么互不影响。静态方法是类锁,即本类的Class对象。同步方法无法指定锁资源,要么是this锁,要么是Class锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        Thread t1 = new Thread(()->{
            test.synFunction();
        });
        Thread t2 = new Thread(()->{
            test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(()->{
            Test.synFunction();
        });
        Thread t2 = new Thread(()->{
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}
    }
}

同步块

同步代码块可以指定锁对象,非静态方法可以指定任意的对象锁,或者任意的类锁。但静态方法只能使用任意的类锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test lock = new Test();
        Thread t1 = new Thread(() -> {
            lock.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (this) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction(lock1);
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction(lock2);
        });
        t1.start();
        t2.start();
    }
    public void synFunction(Object lock) {
        synchronized (lock) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (Test.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction();
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction() {
        synchronized (Object.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}

死锁

当多个线程竞争锁时,可能会导致死锁。一个线程由于没有得到一个锁而阻塞它也不会释放已经获取的锁。方法1获取锁的顺序是Test.class,Object.class。方法2获取锁的顺序是Object.class,Test.class。程序会陷入死锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction1();
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction2();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction1() {
        synchronized (Test.class) {// 类锁
            try {
                System.out.println("synFunction1-------------AAAAAAAAAAAAA");
                synchronized (Object.class) {// 类锁
                    try {
                        System.out.println("synFunction1-------------bbbbbbbbbbbbb");
                    } catch (Exception e) {
                    }
                }
            } catch (Exception e) {
            }
        }
    }
    public static void synFunction2() {
        synchronized (Object.class) {// 类锁
            try {
                System.out.println("synFunction2-------------AAAAAAAAAAAAA");
            } catch (Exception e) {
            }
            synchronized (Test.class) {// 类锁
                try {
                    System.out.println("synFunction2-------------bbbbbbbbbbbbb");
                } catch (Exception e) {
                }
            }
        }
    }
}

优先级

不是所有线程创建时都是均等的,每个线程都有一个优先级,指定从0-10的整数。当多个线程运行时,虚拟机通常只运行最高优先级的线程,但这并不是一个严格的规则。在Java中10是最高优先级,0是最低优先级。默认优先级为5.并不是所有操作系统都支持这11个优先级。例如Windows只有7个优先级。优先级(1,2)(3,4)(6,7)(8,9)会做同样的处理。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction("bbbbbbbbbb");
        });
        t2.setPriority(9);
        t1.setPriority(1);
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        System.out.println(name+"--------------");
    }
}

暂停

为了能让其他线程有机会运行,一个线程有8中方式可以暂停或者指示它准备暂停。

可以对IO阻塞

要让网络程序中的线程自动放弃CPU控制权,最常见的方式是IO阻塞。由于CPU比网络和磁盘快的多,网络程序经常会在等待数据从网络到达或向网络发送数据时阻塞。即使只阻塞几毫秒,这一点时间也足够其他线程用来完成重要的任务。

可以对同步对象阻塞

线程在进入一个同步方法或代码块时也会阻塞。如果这个线程没有所同步对象的锁,而其他线程拥有这个锁,这个线程就会暂停,直到锁被释放为止。如果这个锁永远不会释放,那么这个线程会永久停止。

可以放弃

调用Thread.yield()静态方法可以做到显试的放弃线程控制权,这将通知虚拟机,可以优先执行其他线程。放弃并不会释放这个线程拥有的锁,因此在理想情况下被放弃的线程不要做任何的同步。如果等待运行的其他线程都是因为这个线程所拥有的同步资源而阻塞,那么这些线程将不能运行。实际上,控制权将回到唯一可以运行的线程,即刚刚放弃的这个线程,这很大程度上失去了放弃的意义。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        for (int i = 0;; i++) {
            Thread.yield();
            System.out.println(name + "--------------" + i);
        }
    }
    public static void synFunction2(String name) {
        for (int i = 0;; i++)
            System.out.println(name + "--------------"+i);
    }
}

可以休眠

休眠是更有利的放弃方式。放弃只是表示线程愿意暂停,让其他有相同优先级的线程有机会运行,而进入休眠的线程有所不同,不管有没有其他线程准备运行,休眠线程都会暂停。这样一来,不只是其他有相同优先级的线程会得到机会,还会给较低优先级的线程运行机会。不过进入休眠的线程仍然拥有它已经获得得所有锁。因此其他需要相同锁得线程依然会阻塞,要避免在同步方法或块内让线程休眠。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 10);
        } catch (Exception e) {
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}
package com.datang.bingxiang.demo;
import java.util.concurrent.TimeUnit;
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 3, 999999);//3000毫秒+999999毫秒(第二个参数不能超过999999,也就是不能超过1毫秒)
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}

可以连接另一个线程

连接线程(既调用join()方法得线程A)等待被连接的线程(join()方法所属的线程对象B)执行完毕后才会执行。在A线程调用B线程的join()A线程会等待B线程执行结束后才会继续执行。要注意的是A线程并不会释放已经获取的锁资源。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa",t2);
        });

        t1.start();
        t2.start();
    }
    public  static void synFunction(String name,Thread t) {
        try {
            t.join();
            //t.join(1000);
            //t.join(1000,999999);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
    public  static void synFunction2(String name) {
        try {
            Thread.sleep(1000*3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
}

可以等待一个对象

线程可以等待一个它锁定的对象.在等待时,它会释放这个对象的锁并暂停,直到它得到其他线程的通知.另一个线程以某种方式修改这个对象,通知等待对象的线程,然后继续执行.等待会暂停执行,直到一个对象或资源到达某种状态.实际上,要等待某个特定的对象,希望暂停的线程首先必须使用synchronized获得这个对象的锁,然后调用这个对象的三个重载wait()方法之一.

public class Demo {
    public static void main(String[] args) throws Exception {
        Demo d = new Demo();
        Thread t1 = new Thread(() -> {
            d.a();
        });
        Thread t2 = new Thread(() -> {
            d.b();
        });
        t1.start();
        t2.start();
    }
    boolean flag = true;
    public synchronized void a() {
        try {
            while (true) {
                if (flag) {
                    System.out.println("执行AAAAAAAAAAA");
                    flag = false;
                } else {
                    wait();//等待,不限制等待时间
                    //wait(1000);//等待指定的时间,没有被notify唤醒也可以自己退出等待
                    //wait(1000,999999);//毫秒+纳秒的等待时间
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
    public synchronized void b() {
        try {
            while (true) {
                if (!flag) {
                    System.out.println("执行BBBBBBBBBBB");
                    flag = true;
                } else {
                    wait();
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
}

可以结束

线程要以合理的方式放弃CPU控制权,一种方式是结束.当run()方法返回线程时,线程将撤销,其他线程可以接管CPU.在网络应用程序中,包装一个阻塞操作的线程往往会这么做,例如线程从服务器下载一个文件,这样应用程序的其他部分就不会被阻塞.另一方面,如果run()方法太简单,总是很快结束,而不会紫色,那就存在一个很实际的问题:到底有没有必要生成一个线程.虚拟机在建立和撤销线程时会有很大的开销.如果线程会在极端的时间内结束,那么使用一次简单的方法调用而不是单独的线程可能会结束的更快.

可以被更高优先级线程抢占

Thread的setPriority(int priority)设置线程的优先级.

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java网络编程实现多线程聊天

    本文实例为大家分享了Java网络编程实现多线程聊天的具体代码,供大家参考,具体内容如下 聊天程序如果是单线程,会导致没人只能说一句,并且说了以后,必须等到另一个人的回复,才能说第二句.收发都在主线程中,不能同时进行. 解决方法: 将收发放到两个不同的线程 1. SendThread 发送消息线程 2. RecieveThread 接受消息线程 3. Server一旦接受到连接,就启动收发两个线程 4. Client 一旦建立了连接,就启动收发两个线程 多线程聊天 1 SendThread pac

  • Java网络编程UDP实现多线程在线聊天

    本文实例为大家分享了Java实现多线程在线聊天的具体代码,供大家参考,具体内容如下 上一篇博客通过UDP实现了聊天,但只能单方面发送消息,这次实现了多线程在线聊天,也就是可以双方互发消息. 发送消息: package com.kuang.chat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket;

  • Java网络编程UDP实现消息发送及聊天

    TCP可以实现聊天,UDP也可以实现消息发送及聊天.不同的是,TCP需要有服务端和客户端的连接,但UDP不需要,只需要有发送方和接收方即可. 一.实现消息发送 发送方: package com.kuang.lesson03; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; //不需要连接服务器

  • Java网络编程TCP实现聊天功能

    网络编程TCP实现聊天的前提还需要掌握IO流,话不多说,直接上代码! 客户端: package com.kuang.lesson02; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; //客户端 public class TcpClientDemo01 { public static void main(String[] ar

  • Java网络编程TCP实现文件上传功能

    本文实例为大家分享了Java网络编程TCP实现文件上传的具体代码,供大家参考,具体内容如下 上一篇博客,用网络编程TCP 实现聊天,这次实现文件上传. 客户端: package com.kuang.lesson02; import java.io.*; import java.net.InetAddress; import java.net.Socket; //客户端 public class TcpClientDemo2 { public static void main(String[] a

  • 新手初学Java网络编程

    目录 运行线程 回调 同步方法 同步块 死锁 优先级 暂停 可以对IO阻塞 可以对同步对象阻塞 可以放弃 可以休眠 可以连接另一个线程 可以等待一个对象 可以结束 可以被更高优先级线程抢占 总结 运行线程 创建Thread的子类 public class ThreadChild extends Thread { @Override public void run() { while (true) { System.out.println("run"); } } } public cla

  • 老生常谈Java网络编程TCP通信(必看篇)

    Socket简介: Socket称为"套接字",描述IP地址和端口.在Internet上的主机一般运行多个服务软件,同时提供几种服务,每种服务都打开一个Socket,并绑定在一个端口上,不同的端口对应于不同的服务.Socket和ServerSocket类位于java.net包中.ServerSocket用于服务端,Socket是建立网络连接时使用的.连接成功时,应用程序两端都会产生一个Socket实例,通过操作这个实例完成所需会话. Socket常用方法: -int getLocalP

  • Java网络编程之简单的服务端客户端应用实例

    本文实例讲述了Java网络编程之简单的服务端客户端应用.分享给大家供大家参考.具体如下: 在Java中,我们使用java.net.Socket及其相关类来完成有关网络的相关功能.Socket类非常简单易用,因为Java技术隐藏了建立网络连接和通过连接发送数据的复杂过程.下面所说的内容只适用于TCP协议. 一.连接到服务器 我们可以使用Socket类的构造函数来打开一个套接字,如 Socket sk = new Socket("210.0.235.14",13); 其中,210.0.23

  • java网络编程基础知识介绍

    网络基础知识 1.OSI分层模型和TCP/IP分层模型的对应关系 这里对于7层模型不展开来讲,只选择跟这次系列主题相关的知识点介绍. 2.七层模型与协议的对应关系 网络层 ------------ IP(网络之间的互联协议) 传输层 ------------ TCP(传输控制协议).UDP(用户数据报协议) 应用层 ------------ Telnet(Internet远程登录服务的标准协议和主要方式).FTP(文本传输协议).HTTP(超文本传送协议) 3.IP地址和端口号 1.ip地址用于

  • Java网络编程实现的简单端口扫描器示例

    本文实例讲述了Java网络编程实现的简单端口扫描器.分享给大家供大家参考,具体如下: 在计算机网络的学习中,不由得觉得这门课的零碎知识点异常之多,同时因为学习的课本是老外的教材--自顶向下方法,因此学习起来不免觉得吃力,但是从老外的教材里更能从一定高度理解计算机网络的知识体系,也是乐在其中,同时做英语的习题感觉也很有趣味,从各方面来说可以说是获益良多,认识了很多专业词汇.节课之后,便想做一个简单的端口扫描器,用的语言是java,因为实现界面很简单,同时也有封装好的Socket类可以使用,主要思路

  • 基于Java网络编程和多线程的多对多聊天系统

    1.前言 程序实现基于星型结构(服务器接收来自各个客户端发送的信息,然后将信息传递给其他客户端界面并在其他客户端界面显示发送的信息) 2.类图 3.代码 客户端代码: package netProgram; import java.io.IOException; import java.net.Socket; import java.net.SocketAddress; public class Client implements ScreenInputInterface{ private So

  • Java网络编程之基于TCP协议

    一.单向通信 功能:客户端发送一句话到服务器: 客户端: public class TestClient {//客户端 //这是一个main方法,是程序的入口: public static void main(String[] args) throws IOException { //1.创建套接字:指定服务器的ip和端口号: Socket s = new Socket("192.168.199.217",8888); //2.对于程序员来说,向外发送数据 感受 -->利用输出流

  • Java网络编程实例——简单模拟在线聊天

    1.前提知识 需要知道简单的IO流操作,以及简单的UDP发送数据包的原理. 需要用到的类:DatagramSocket.DatagramPacket UDP数据包基于DatagramSocket发送和接收,DatagramPacket用于封装数据包 看下案例: 客户端发送消息: 正常情况下从控制台读信息,封装到DatagramPacket之中,再由DatagramSocket的send方法发出 读取到bye的时候退出聊天 public class UdpOnlineClient { public

  • 详解Java网络编程

    一.网络编程 1.1.概述 1.计算机网络是通过传输介质.通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统.网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输.Java语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程. 2.Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序. 3.Java提供的网络类库,可以实现无痛的网络连接,联

随机推荐