`
收藏列表
标题 标签 来源
对称加密 Java基于对称密钥的加密解密
package com.liusong;

/**
 * 对称密钥的生成以及以对象序列化的方式保存
 *
 */

import java.io.*;
import javax.crypto.*;

public class Skey_DES 
{
    public static void main( String[] args ) throws Exception
    {
        //获取密码生成器
    	//算法名称可以是Blowfish,DES,DESede,HmacMD5或HmacSHA1
    	//DES是目前最常用的对称加密算法,改进了的DES算法是DESede,
    	//Blowfish的密钥长度可达448位
    	KeyGenerator kg = KeyGenerator.getInstance("DESede");
    	
        //初始化密码生成器
    	//省略该步骤,会根据算法自动生成使用的默认的密钥长度
    	//DES算法,密钥必须是56位
    	//若是AES,可以是128,192,256位
    	//若是Blowfish,则可以是32~448之间可以被8整除的数
    	//HmacMD5和HmacSHA1默认的长度是64字节
    	kg.init(168);
    	//生成密钥
    	SecretKey k = kg.generateKey();
    	//通过对象序列化方式将密钥保存在文件中
    	FileOutputStream f = new FileOutputStream("key1.dat");
    	ObjectOutputStream b = new ObjectOutputStream(f);
    	b.writeObject(k);
    	
    }
}
密钥生成 密钥生成
public class SecurityKeyGenerator
{

    public static void main(String[] args)
        throws IOException, NoSuchAlgorithmException, ClassNotFoundException, NoSuchPaddingException,
        InvalidKeyException, IllegalBlockSizeException, BadPaddingException
    {
        // InputStream in = System.in;
        // InputStreamReader isr = new InputStreamReader(in);
        // BufferedReader br = new BufferedReader(isr);
        // String[] para = br.readLine().split(" ");
        // String s = para[0];// 明文
        // int key = Integer.parseInt(para[1]); // 移动位数

        // 创建对称密钥生成器
        KeyGenerator kg = KeyGenerator.getInstance("DESede");
        // 指定密钥长度
        kg.init(168);
        // 生成密钥,用于加密和解密
        SecretKey k = kg.generateKey();

        // 将密钥保存到文件中(以对象方式存储)
        FileOutputStream f = new FileOutputStream("key1.dat");
        ObjectOutputStream b = new ObjectOutputStream(f);
        b.writeObject(k);

        // 获取密钥编码格式(以字节方式存储)
        byte[] kb = k.getEncoded();
        // 将编码格式存入文件中
        FileOutputStream f2 = new FileOutputStream("keykb1.dat");
        f2.write(kb);

        System.out.println("密钥:");
        // 打印密钥编码中的内容
        for (int i = 0; i < kb.length; i++)
        {
            System.out.print(kb[i] + ",");
        }

        // /////////////////用密钥加密字符串
        // 得到密钥
        FileInputStream f22 = new FileInputStream("key1.dat");
        ObjectInputStream b2 = new ObjectInputStream(f22);
        Key k2 = (Key)b2.readObject();

        // 初始化密码器,使用DESede加密算法,密钥要是使用DESede计算出来的密钥
        Cipher cp = Cipher.getInstance("DESede");
        cp.init(Cipher.ENCRYPT_MODE, k2);
        // 将将要加密的明文转换成字节,进行加密
        String minwen = "Hello World!";
        byte ptext[] = minwen.getBytes("UTF8");
        byte ctext[] = cp.doFinal(ptext);
        System.out.println();
        System.out.println("密文:");
        for (int i = 0; i < ctext.length; i++)
        {
            System.out.print(ctext[i] + ",");
        }
        FileOutputStream fmiwen = new FileOutputStream("SEnc.dat");
        fmiwen.write(ctext);

        // // /////////////////用密钥解密刚才加密的字符串
        // 获取密文
        FileInputStream fin = new FileInputStream("SEnc.dat");
        int num = fin.available();
        byte[] ctextin = new byte[num];
        fin.read(ctextin);

        System.out.println();
        System.out.println("读取到的密文是:");
        for (int i = 0; i < ctextin.length; i++)
        {
            System.out.print(ctextin[i] + ",");
        }

        // 获取密钥
        FileInputStream f222 = new FileInputStream("keykb1.dat");
        int num2 = f222.available();
        byte[] keykb = new byte[num2];
        f222.read(keykb);
        SecretKeySpec kjiemi = new SecretKeySpec(keykb, "DESede");

        // 对密文进行解密
        Cipher cpjiemi = Cipher.getInstance("DESede");
        cpjiemi.init(Cipher.DECRYPT_MODE, kjiemi);
        byte[] ptextjiemi = cpjiemi.doFinal(ctextin);
        String jiemi = new String(ptextjiemi, "UTF-8");
        System.out.println();
        System.out.println("解密后明文:");
        System.out.println(jiemi);

    }

}


多线程 多线程总结

多线程:
	线程是进程中的一个控制单元。
	一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个控制单元。
	并发运行。如:多线程下载软件。
	
	可以完成同时运行,但是通过程序运行的结果发现,虽然同时运行,但是每一次结果都不一致。


	因为多线程存在一个特性:随机性。
	造成的原因:CPU在瞬间不断切换去处理各个线程导致的。
	可以理解成多个线程在抢cpu资源。

	如果在程序中创建一个新的控制单元呢?

	Java对线程有自己描述,而且在调用系统资源。
	该描述的类是Thread。只要创建Thread类的对象即可在内存中建立新的控制单元。

	但是创建线程的目的是为了运行自定义的代码。
	自定义的代码如何和多线程相结合呢?
	通过start方法明确,线程是在执行run方法。
	那么只要将线程需要运行的代码存入到run方法中即可。
	只要继承Thread类并复写该run方法即可。

	创建线程的第一种方式:继承Thread类;
	1,定义Thread类的子类。创建子类对象,就是在内存中建立了控制单元。
	2,复写Thread类中的run方法。将多线程要运行的代码存入其中。
	3,调用线程Thread中的start方法开启线程,并让jvm运行run方法。

	线程的四种状态:
	1,被创建.new Thread类或者Thread类的子类对象。
	2,通过start方法,让线程进入到了运行状态。
	3,线程存活的情况,可以不运行,因为到了冻结状态。
	4,消亡,线程执行的代码结束。

	如何获取当前线程对象呢?
	通过Thread类中的静态方法:Thread currentThread()。
	获取线程的名称 getName():默认是Thread-编号。

	class Demo extends Thread
	{
		public void run()
		{
			for(int x=0; x<20; x++)
			{
				System.out.println(Thread.currentThread().getName());
			}
		}
	}

	main()
	{
		Demo d1 = new Demo();
		Demo d2 = new Demo();
		//d1.run();
		//d2.run();当直接对象调用run方法,其实是一共有三个线程,
			//但是只有主线程在运行。所以打印的都是主线程的名称main。
		d1.start();
		d2.start();//有三个线程,并三个线程都处于运行状态,在互相抢资源运行。


		for(int x=0; x<30; x++)
		{
			System.out.println(Thread.currentThread().getName());
		}
	}

	class Ticket extends Thread
	{
		private int num = 100;
		public void run()
		{
			while(true)
			{
				if(num>0)
				{
					System.out.println(Thread.currentThread().getName()+"..."+num--);
				}
			}
		}
	}
	main()
	{
		Ticket t1 = new Ticket();
		Ticket t2 = new Ticket();
		Ticket t3 = new Ticket();
		Ticket t4 = new Ticket();
		t1.start();
		t2.start();
		t3.start();
		t4.start();

		//结果是将票进行打印,但是出现了400张票。
		因为每一个ticket对象中都有自己的num。
		可以通过将num修饰成static的,这是可以的,但是通常不建议定义static因为生存周期过长。


		Ticket t1 = new Ticket();
		
		t1.start();
		t1.start();
		t1.start();
		t1.start();

		//一个线程开启多次,会造成无效的线程状态异常。IllegalThreadStateException


	}


	什么时候需要多线程呢?
	当多部分代码需要同时运行时,就需要使用多线程技术。
	聊天软件的例子。发送区域和接收数据区域就是同时运行的。

------------------------------------

两种创建方式:
	1,继承Thread类。复写run方法,通过start方法开启线程。并让jvm调用run方法。
	2,实现Runnable接口;
		2.1定义类实现Runnable接口。
		2.2复写接口中run方法。
		2.3通过Thread类建立线程对象。
		2.4将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
			目的:让线程可以执行执行的接口子类的run方法。
		2.5调用Thread类的start方法开启线程。
	
	这两种方式区别:
	线程代码存放的位置不同,一个存放在Thread类的子类中。一个存在Runnable接口的子类中。

	第二种方式有什么好处呢?
	1,将资源对多线程共享。
	2,避免了单继承的局限性。
		
	-----------------
	线程的安全问题。
	造成的原因是什么?
	多条语句同时操作通一个成员变量,这些语句被多个线程分开执行会造成成员数据的错误。
	int num = 100;
	public void run()
	{
		while(true)
		{
			if(num>0)
				-->0  -->1
				System.out.println(num--);
		}
	}


	如何解决呢?
	可以通过同步的方式解决线程安全问题。
	原理:
	将出现安全问题的语句存放同步区域中,同步区域的好处在于给该区域加锁。
	这样就保证了某一时刻只有一个线程在同步区域内执行多条语句。

	弊端:消耗资源,对效率有降低。

	如果同步嵌套,容易出现死锁。

	在书写同步的时候前提:
	1,需要两个或者两个以上的线程。
	2,多个线程必须使用同一个锁。

	同通过一个比喻理解同步:火车上的卫生间。

	同步有两种表现形式:
	1,同步代码块:一个单独的封装区域。通过同步关键字定义的。锁是自定义的任意对象。
	2,同步函数:将同步关键字作为修饰符定义在函数上,让函数具备了同步的特性,使用的锁this。
		特例:静态同步函数使用的是什么锁呢?字节码文件所属对象。类名.class.

	单例设计模式的中的懒汉式设计模式的特点:
	class Single
	{
		private static  Single s = null;
		private Single(){}
		public static Single getInstance()
		{
			if(s == null)
				
				s = new Single();
			return s;
		}
	}
	这种懒汉式当多线程并发访问该方法时,会出现线程安全问题。

	if(s == null)
		-->0  -->1		
		s = new Single();
	为了解决这个问题,将这个方法修饰为同步的。
	public static synchronized Single getInstance()
	{
		if(s == null)			
			s = new Single();
		return s;
	}

	这是修饰虽然解决了安全问题,但是效率较低。因为每一个线程访问该方法时,都要判断Single.class这个锁。

	优化一下。通过双重判断的形式。
	public static  Single getInstance()
	{
		if(s==null)
		{
			--.0 --.1
			synchronized(Single.class)
			{
				if(s == null)			
					s = new Single();
			}
		}
		return s;
	}
		
	---------
	线程间的通信。
	多个线程在操作同一个资源。但是操作的动作不一致。
	需要对这个动作分别进行描述,并存放在不同的run方法。

	通常可以可以将资源作为参数传递给run方法做在类的构造函数。

	wait(),notify(),notifyAll().也可以通过比喻:儿时的抓人游戏。
	
	notify():唤醒的是线程池中的第一个。

	这些方法都使用在同步中。
	用于操作线程。

	这些方法为什么定义在了Object类中?
	因为这三个方法,需要标识线程所属的锁。lock.wait(),lock.notify();
	而锁可以是任意对象,那么任意对象可以调用的方法定义在Object类中。

	wait(),sleep()的特点:
	wait():释放资源,释放锁。
	sleep():释放资源,不释放锁。

	-------------------------

	线程的停止:
	因为stop方法过时了。
	所以只有一方式:run方法结束。
	run方法中通常都会定义循环。
	1,定义结束标记。只要控制住循环,就可以结束run方法。
	但是这种情况也有局限:当线程处于了冻结状态,是不会执行标记的。
	2,interrupt():强制将冻结状态清除,让线程从冻结状态转回运行状态,就有机会执行到标记。
			但这种方式会发生异常。InterruptedException.
			可以作用于被wait,sleep,join、方法冻结的线程。
	
	
	-------------------------
	setPriority(int):设置线程的优先级。级别:1~10.
			有三个常量可用。MIN_PRIORITY=1,MAX_PRIORITY=10,NORM_PRIORITY=5
			所有线程默认是都是5。
	
	setDaemon(boolean):将线程标记成守护线程。
				有什么特点呢?当前台线程都结束后,守护线程自动结束。
				注意:必须要用的线程开启前。
	
	join():加入线程。当某一个线程A在执行时,执行到了B.join().那么A会释放出资源,
			等待B线程运行结束,A在恢复到运行状态。

	static void yield():让线程临时暂停,时间较短,只为延缓线程的速度。


	聊天程序使用了多线程技术。

	web服务器也使用了多线程技术。
	将每一个访问web服务端的客户端封装成一个线程。可以让多个客户端并发访问服务器。
		
	对于已有的服务端软件,如Tomcat。内部就封装了多线程技术。

---------------------------------------------



左连接和右连接 Oracle PL-SQL中 左连接和右连接用法
在Oracle PL-SQL中,左连接和右连接以如下方式来实现
   查看如下语句:
SELECT emp_name, dept_name
FORM Employee, Department
WHERE Employee.emp_deptid(+) = Department.deptid

   此SQL文使用了右连接,即“(+)”所在位置的另一侧为连接的方向,右连接说明等号右侧的所有记录均会被显示,无论其在左侧是否得到匹配,也就是说上例中无论会不会出现某个部门没有一个员工的情况,这个部门的名字都会在查询结果中出现。

反之:
SELECT emp_name, dept_name
FORM Employee, Department
WHERE Employee.emp_deptid = Department.deptid(+)则是左连接,无论这个员工有没有一个能在Department表中得到匹配的部门号,这个员工的记录都会被显示


有两个表T1和T2,两个表除了主键索引外均无其他索引,这两个表由T1.F1(主键),T2.F2(主键)进行左连接,SQL语句有两种写法:
1. SELECT * FROM T1,T2 WHERE T1.F1=T2.F2(+)
2. SELECT * FROM T1 LEFT JOIN T2 ON T1.F1=T2.F2

当查看1的执行计划时发现T1为全表扫描,T2为索引扫描。
当查看2的执行计划时发现两个表均为全表扫描。

介绍表连接,更确切的说是inner joins內连接.
內连接仅选出两张表中互相匹配的记录.因此,这会导致有时我们需要的记录没有包含进来。
为更好的理解这个概念,我们介绍两个表作演示。苏格兰议会中的政党表(party)和议员表(msp)。

party(Code,Name,Leader)
Code: 政党代码
Name: 政党名称
Leader: 政党领袖

msp(Name,Party,Constituency)
Name: 议员名
Party: 议员所在政党代码
Constituency: 选区

在介绍左连接、右连接和全连接前,有一个数据库中重要的概念要介绍一下,即空值(NULL)。

A left join(左连接)包含所有的左边表中的记录甚至是右边表中没有和它匹配的记录。
同理,也存在着相同道理的 right join(右连接),即包含所有的右边表中的记录甚至是左边表中没有和它匹配的记录。
而full join(全连接)顾名思义,左右表中所有记录都会选出来。

讲到这里,有人可能要问,到底什么叫:包含所有的左边表中的记录甚至是右边表中没有和它匹配的记录。
Ok,我们来看一个实例:

SELECT msp.name, party.name
FROM msp JOIN party ON party=code

这个是我们上一节所学的Join(注意:也叫inner join),这个语句的本意是列出所有议员的名字和他所属政党。
你亲自执行一下该语句,看看结果是什么。

很遗憾,我们发现该查询的结果少了两个议员:Canavan MSP, Dennis。为什么,因为这两个议员不属于任
和政党,即他们的政党字段(Party)为空值。那么为什么不属于任何政党就查不出来了?这是因为空值在
作怪。因为议员表中政党字段(Party)的空值在政党表中找不到对应的记录作匹配,即
FROM msp JOIN party ON party=code 没有把该记录连接起来,而是过滤出去了。
在该短语中,msp在Join的左边,所有称为左表。party在Join的右边,所有称为右表。

Ok,现在再看看这句话,“包含所有的左边表中的记录甚至是右边表中没有和它匹配的记录”,
意思应该很明白了吧。执行下面这个语句,那两个没有政党的议员就漏不了了。

SELECT msp.name, party.name
FROM msp LEFT JOIN party ON party=code

关于右连接,看看这个查询就明白了:

SELECT msp.name, party.name
FROM msp RIGHT JOIN party ON msp.party=party.code

这个查询的结果列出所有的议员和政党,包含没有议员的政党,但不包含没有政党的议员。

那么既要包含没有议员的政党,又要包含没有政党的议员该怎么办呢,对了,全连接(full join)。

SELECT msp.name, party.name
FROM msp FULL JOIN party ON msp.party=party.code

Global site tag (gtag.js) - Google Analytics