1.如何解决多线程的安全问题? 校验一个多线程程序是否有安全问题的隐患的前提条件: 1)当前程序是否是多线程环境 2)是否有共享数据 3)是否有多条语句对共享数据进行操作
-
锁对象格式: synchronized(锁对象){ 针对多条语句对共享数据操作代码; } 锁对象:一定要同一个锁(每个线程只能使用同一把锁) 售票问题 package org.westos_05;
public class SellTicket implements Runnable {
//定义100张票
private int tickets = 100 ;
private Object obj = new Object() ;
private Demo d = new Demo() ;
@Override
public void run() {
while(true) {
//t1,t2,t3
synchronized(d) { //门的开和关
//t1进来,门会关掉
//t2进来,门关掉
//t3进来,门关掉
if(tickets>0) {
try {
//0.1
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+"正在出售第"+(tickets--)+"张票");
//窗口1正在出售第100张票
//窗口2正在出售第99张票
//窗口3正在出售98张票
//....
//虽然加入延迟操作,就是synchronized,不会存在0或者负票了
}
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
//创建资源类对象(共享资源类/目标对象)
SellTicket st = new SellTicket() ;
//创建线程类对象
Thread t1 = new Thread(st, "窗口1") ;
Thread t2 = new Thread(st ,"窗口2") ;
Thread t3 = new Thread(st, "窗口3") ;
//启动线程
t1.start();
t2.start();
t3.start();
}
}
还可以将锁对象进行包装,如果包装成静态类,锁对象为类名.class; 如果是非静态类,锁对象为this ; 3. //线程安全的类 StringBuffer sb = new StringBuffer() ; Vector<String> v = new Vector<String>() ; Hashtable<String, String> hm = new Hashtable<String,String>() ;
//Vector<String>它线程安全的类,还是不习惯使用这个集合,通过ArrayList集合:线程不安全的类
List<String> array = new ArrayList(); //线程不安全的类
//public static <T> List<T> synchronizedList(List<T> list)
//返回指定列表支持的同步(线程安全的)列表
List list = Collections.synchronizedList(array) ; //线程安全的方法
4. // Jdk5.0以后,java提供了一个具体的锁: 接口:Lock
private Lock lock= new ReentrantLock(); //显示获取锁的前提,一定要创建Lock接口对象
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构
可以使用Lock锁进行具体的锁定操作类 提供了具体的实现类:ReentrantLock 加锁并且去释放锁
package org.westos_07;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
public class SellTicket implements Runnable {
// 定义票
private int tickets = 100;
// Object obj = new Object();
// Jdk5.0以后,java提供了一个具体的锁: 接口:Lock
private Lock lock= new ReentrantLock(); //显示获取锁的前提,一定要创建Lock接口对象
@Override
public void run() {
while (true) {
try { //try...finally
lock.lock(); // 获取锁 syncrhonized(obj)
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
}
} finally {//释放锁
if(lock!=null) {
lock.unlock();
}
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
SellTicket st = new SellTicket() ;
Thread t1 = new Thread(st,"窗口1") ;
Thread t2 = new Thread(st,"窗口2") ;
Thread t3 = new Thread(st,"窗口3") ;
//启动线程
t1.start();
t2.start();
t3.start();
}
}
5.消费者生产者问题解密死锁;
package org.westos_11;
public class Student {
String name ;
int age ;
boolean flag; //默认没有数据,如果是true,说明有数据
}
package org.westos_11;
//消费者线程 public class GetThread implements Runnable { private Student s ;
public GetThread(Student s) {
this.s = s ;
}
@Override
public void run() {
//输出该学生数据
// Student s = new Student() ; while(true) { synchronized (s) { //如果本身消费者有数据 if(!s.flag) { try { s.wait();//和网络编程中TCP编程里面的accept() 都属于阻塞式方法 //消费线程等待,等待该线程先输出这些数据(立即释放锁对象)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name +"----"+s.age);//高圆圆---27
//如果没有数据类,
s.flag = false ;
//通知t1线程,赶紧产生数据
s.notify(); //唤醒单个线程
}
//张杨---27
}
}
}
public SetThread(Student s) {
this.s = s ;
}
//定义一个变量
private int x = 0 ;
@Override
public void run() {
//设置学生数据
// Student s = new Student() ; while(true) { synchronized (s) { //判断有没有数据的情况 if(s.flag) {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x%2 ==0) {
s.name = "高圆圆" ; //高圆圆---27
s.age = 27 ;
}else {
s.name = "张杨";
//张杨
s.age = 28 ;
}
x++ ;
//如果有数据了,更改flag值
s.flag = true ;//有数据了
//通知t2线程消费数据,唤醒
s.notify(); //唤醒t2线程,唤醒之后t1,t2都互相抢占
}
}
}
}
public class StudentDemo {
public static void main(String[] args) {
//针对同一个对象进行操作
Student s = new Student() ;
//创建线程类对象
SetThread st = new SetThread(s) ;
GetThread gt = new GetThread(s) ;
//创建线程了对象
Thread t1 = new Thread(st) ; //生产者
Thread t2 = new Thread(gt) ;//消费者
//启动线程
t1.start();
t2.start();
}
}public class StudentDemo {
public static void main(String[] args) {
//针对同一个对象进行操作
Student s = new Student() ;
//创建线程类对象
SetThread st = new SetThread(s) ;
GetThread gt = new GetThread(s) ;
//创建线程了对象
Thread t1 = new Thread(st) ; //生产者
Thread t2 = new Thread(gt) ;//消费者
//启动线程
t1.start();
t2.start();
}
}
-
线程池问题
package org.westos_13;
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
线程池:多个线程执行完毕,它会重新回到线程池中,等待被利用,不会变成垃圾! 和线程池有关的类 类 Executors: 一种工厂类
方法:
和线程池的创建有关系
public static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池
ExecutorService:可以执行异步任务 创建一个线程池,执行接口中的方法 提交:Future<?> submit(Runnable task) <T> Future<T> submit(Callable<T> task)提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future Future:接口 Future 表示异步计算的结果
线程池调用完毕可以关闭的
void shutdown():关闭之前,会提交刚才的任务
public class ExceutorsDemo {
public static void main(String[] args) {
//创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(2) ;//创建一个线程池中包含了2条线程
//提交和Runnable接口的方法或者Callable(提交任务)
pool.submit( new MyRunnable()) ;
pool.submit( new MyRunnable()) ;
//pool-1-thread-2 :线程池-池数-线程类对象的描述-编号(从1开始)
//关闭线程池
pool.shutdown();
}
}
package org.westos_13;
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int x = 0 ; x < 100 ; x ++) {
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
-
简单工厂模式--->静态工厂方法模式
设计一个工厂类: 工厂类提供一些静态方法,间接的去创建具体的对象
优点: 不需要在创建具体类的对象,而是把创建的工作交给了工厂类来创建! 弊端:如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护
- 工厂方法模式 提供一个抽象类(抽象工厂)还需要提供一个接口(工厂接口),每一个具体的类都有对应的工厂类(实现工厂接口) 具体对象的创建工作由继承抽象工厂的具体类实现
优点:
客户端不需要在负责对象的创建(不需显示创建具体对象),从而明确了各个类的职责,
如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强 了系统的扩展性
弊端:
书写代码量大了!
9.
设计模式之单例模式
单例模式核心思想:某些类的对象在创建的时候 ,在系统内存始终只有一个对象!
单例模式分类:
1)饿汉式 2)懒汉式(类似于多线程环境..) 两种分类在设计上几乎一样
-
饿汉式: 在加载那个类的时候,对象的创建工作就已经完成了!
1)定义个类,将该类的无参构造方法私有化 2)在该类的成员位置创建该类对象 并且一定要私有化,防止外界更改这个对象 3)在该类中提供静态成员方法(返回值就是创建的那个对象),能被当前类直接调用,static修饰
-
懒汉式: 符合单例模式核心思想 1)自定义一个类,将无参构造私有化 2)在成员位置声明变量 3)提供公共静态功能,在里面判断的创建该类对象,返回该类对象
如果是开发中,那么就使用饿汉式(饿汉式它不会出现问题的单例模式) 如果是面试中,那么使用懒汉式(因为他是可能出现问题的一种单例模式)
-
面试题: 你使用过单例模式吗?简单介绍一种单例模式,请用代码设计 面试官想问的是:使用设计单例的懒汉式,能否想到使用同步机制解决线程的安全问题..
懒汉式(延迟加载 -->懒加载) 可能会出现问题 ---> 多线程的问题 --->校验多线程安全问题的标准 1)是否是多线程环境 2)是否有共享数据 3)是否有多条语句对共享数据进行操作 (使用同步机制进行操作)
13.网络的概念 计算机网络: 多台计算机通过网络协议,实现网络资源共享和信息传递!
http://localhost:端口号 (80)www.baidu.com
username:admin password:%AE%.... MD5算法 加密很难解密
网络通信三要素
1)ip地址
2)端口号
3)应该有一些规则(协议UDP/TCP)
举例:
我想和高圆圆聊天...
1)找到她,才能和她说话------>IP地址
2)假设找她了,怎么说呢?
对着她耳朵说话------->port端口号
3)要对她:i love you
假设不懂英文,----->定义规则(协议)
IP地址: 192.168.10.1 (通过8421码将可以由0,1组成的一些数据) 点分十进制法:十进制.十进制.十进制.十进制 书写简单
11000000.0000100....
Ip地址的分类:
IP地址的组成
IP地址 = 网络号码+主机地址
A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
一般情况:国防部/大的国部门
B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
一般情况:大学里面的多媒体教室
C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
私人地址
A类 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址) (2)127.X.X.X是保留地址,用做循环测试用的。 B类 128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。 C类 192.0.0.1---223.255.255.254 192.168.X.X是私有地址 D类 224.0.0.1---239.255.255.254 E类 240.0.0.1---247.255.255.254
127.0.0.1--->表示本地计算机的回环地址 dos ipconfig ping ip地址 是否能通信
声呐系统(二战)
端口号:0~65535有效端口号 0-1024属于保留端口
mysql:3306
协议: UDP协议 --->UDP编程 不需要建立连接通道的 数据大小有限制 不可靠连接 执行效率高 TCP协议 ---->TCP编程 需要建立连接通道 数据大小无限制 可靠连接 执行效率低
打电话:看成TCP协议 建立连接通道
发短信:UDP协议 不需要建立连接通道
- .InetAddress:类表示互联网协议 (IP) 地址
如果一个类中没有构造方法,没有字段,只有成员方法?有什么特征 1)应该有一些静态功能(Math类,Arrays,Collections...) 2)可能符合一种单例模式(饿汉/懒汉) 3)该类中的某些静态成员方法的返回值是该类本身
举例
public class Demo{
public static Demo getDemo(){
new Demo() ;
}
}
常用方法: public static InetAddress getByName(String host) throws UnknownHostException在给定主机名的情况下确定主机的 IP 地址。 参数: 主机名可以是机器名(如 "java.sun.com"),也可以是其 IP 地址的文本表示形式;
-
Udp编程
1)不需要建立连接通道 2)数据大小有限制 3)不可靠连接---->传输速度快!
发送端的开发步骤: 1)创建发送端的Socket对象 2)创建数据,并打包 3)调用当前发送端Socket对象中的发送的方法 4)关闭资源
方法: buf - 包数据。 offset - 包数据偏移量。 length - 包数据长度。 address - 目的地址。 port - 目的端口号。
Udp编程的接收端 开发步骤: 1)创建Socket对象 2)创建一个数据报包(接收容器) 3)调用Socket对象中的接收的方法 4)解析实际传递的数据 5)将解析的数据(ip,数据)展示在控制台上 6)关闭资源 注意: 接收端不要运行多次,会出现异常: java.net.BindException: Address already in use: Cannot bind